2017-02-21 3 views
3

Ich versuche zu verstehen, aus welchen Gründen benötigt die yield-Familie von Funktionen, dass die Klasse standardmäßig konstruierbar ist?Warum benötigt Range-v3 yield den Standardkonstruktor

Im folgenden Beispiel kompiliert die Zeile vnums1 nur, wenn CNum einen Standardkonstruktor hat. Die Zeile vnums2 benötigt keinen Standardkonstruktor.

Ich verwende Visual Studio 2017 und Range-V3-VS2015. Vielen Dank!

#include <range/v3/all.hpp> 

struct CNum 
{ 
    // CNum() = default; 
    explicit CNum(int num) : m_num(num) {} 
    int m_num; 
}; 

int main() 
{ 
    auto ints = ranges::view::ints(0, 10); 

    // this compiles only of CNum has a default constructor 
    auto vnums1 = ints 
     | ranges::view::for_each([](int num) { return ranges::yield_if(num % 2, CNum(num)); }) 
     | ranges::to_vector; 

    // this compiles even if CNum does not have a default constructor 
    auto vnums2 = ints 
     | ranges::view::remove_if([](int num) { return num % 2 == 0; }) 
     | ranges::view::transform([](int num) { return CNum(num); }) 
     | ranges::to_vector; 

    return 0; 
} 

Antwort

2

Wir haben den Code so geändert, dass er nicht DefaultConstructible erfordert. git ziehen und genießen.

+0

Das ist großartig. Vielen Dank. Betreuer von Microsoft/Range-V3-VS2015 übernehmen keine neuen Änderungen von ericniebler/range-v3. Hat jemand Vorschläge, wie ich die neuesten Bits mit VC++ 2017 arbeiten kann? – CodeAndLearn

+0

Leider ist es am besten, wenn Sie den Microsoft/Range-V3-VS2015-Repo auslagern und die Änderungen selbst vornehmen. –

1

Der Grund, warum Sie benötigen Konstruktor auf Standard ranges::yield_if zu verwenden, ist, dass die Maschine den Typ verwendet, erfordert standardmäßig konstruierbar zu sein. Wenn wir den Code anschauen haben wir

struct yield_if_fn 
{ 
    template<typename V> 
    repeat_n_view<V> operator()(bool b, V v) const 
    { 
     return view::repeat_n(std::move(v), b ? 1 : 0); 
    } 
}; 

/// \relates yield_if_fn 
/// \ingroup group-views 
RANGES_INLINE_VARIABLE(yield_if_fn, yield_if) 

Und wir können sehen, dass es view::repeat_n nennt. Mit Blick auf diesen Code erhalten wir

repeat_n_view<Val> operator()(Val value, std::ptrdiff_t n) const 
{ 
    return repeat_n_view<Val>{std::move(value), n}; 
} 

Und wenn wir bei repeat_n_view schauen wir haben

// Ordinarily, a view shouldn't contain its elements. This is so that copying 
// and assigning ranges is O(1), and also so that in the event of element 
// mutation, all the copies of the range see the mutation the same way. The 
// repeat_n_view *does* own its lone element, though. This is OK because: 
// - O(N) copying is fine when N==1 as it is in this case, and 
// - The element is immutable, so there is no potential for incorrect 
// semantics. 

struct repeat_n_view 
    : view_facade<repeat_n_view<Val>, finite> 
{ 
private: 
    friend range_access; 
    Val value_; 
    std::ptrdiff_t n_; 

    // ... 
public: 
    repeat_n_view() = default; 
    constexpr repeat_n_view(Val value, std::ptrdiff_t n) 
     : value_(detail::move(value)), n_((RANGES_EXPECT(0 <= n), n)) 
    {} 
    constexpr std::size_t size() const 
    { 
     return static_cast<std::size_t>(n_); 
    } 
}; 

Wir aus dem Kommentar, dass dies eine Design-Entscheidung war und wegen dieser Entwurf Sie benötigen, um Ihre Art zu sein, Standardkonstruierbar Eric beschreibt den erforderlichen Typ als SemiRegular, der dokumentiert ist als

es muss standardmäßig konstruierbar sein, kopieren und verschieben konstruierbar und zerstörbar.

Verwandte Themen