2016-06-04 12 views
4

Angenommen, wir haben eine Funktion, die std::optional<A> zurückgibt. Was ist dann eine geeignete Methode, um das Ergebnis in der bereichsbasierten for-Schleife zu verwenden? Der einfachste Weg nicht funktioniert:Vorübergehend optional in der range-based for loop Ausdruck

for (auto&& e : a().value()) { 
        // ^--- A&& is returned, so A is destructed 
        // before loop starts 

Dieses Problem würde nicht existieren, wenn wir T optional::value() && statt T&& optional::value() && hätten, aber beide STL und Boost es in einer zweiten Art und Weise definieren.

Was ist ein geeigneter Weg, um mit dieser Situation umzugehen? Ich mag es nicht, beide Lösungen, die ich von (sandbox) einfiel:

std::experimental::optional<A> a() { 
    // ... 
} 

void ok1() { 
    // ugly if type of A is huge 
    for (auto&& e : A(a().value())) { 
    // ... 
    } 
} 

void ok2() { 
    // extra variable is not used 
    // if for some reason we are sure that we have a value 
    // and we skip checks 
    auto&& b = a(); 
    for (auto&& e : b.value()) { 
    // ... 
    } 
} 

// it may be that the best choice is to define 
A aForced() { 
    return A(a().value()); 
} 
+0

Ich schrieb eigentlich eine ganze Post über dieses genaue Verhalten, und ich spreche über verschiedene Optionen, um es in benutzerdefinierten Typen zu lösen, vielleicht finden Sie es interessant: http://www.nirfriedman.com/2016/01/18/schreiben-good-cpp-per-default-in-the-stl /. –

+0

@NirFriedman Ich dachte nie an die gleichen Probleme mit Std :: Get & Co, danke! Und zu Ihrer Information: Der Code, den ich in dieser Frage diskutiere, ist live, also ist Ihr Beitrag wirklich praktisch. Ich verstehe nicht, warum es keine 'std :: copy_of' gibt, als eine Antwort von @ yakk, zumindest wäre es ein guter Weg, Leute dazu zu bringen, auf das Problem zu achten. –

Antwort

2

Dies löst Ihr Problem:

template<class T> 
std::decay_t<T> copy_of(T&& t){ 
    return std::forward<T>(t); 
} 

template<class T, std::size_t N> 
void copy_of(T(&)[N])=delete; 

Dann:

for(auto&& x:copy_of(a().value())) 

Die copy_of Technik im Allgemeinen löst Funktionen Rückgabe von rvalue-Referenzen, die auf for(:) Loops verwendet werden.


Eine Alternative ist das Schreiben value_or_run(T&&, F&&f), die eine Lambda nimmt auch nützlich sein kann. In der F können Sie tun, was Sie wollen, wie werfen, und es gibt eine T nicht eine T&&.

Ähnlich, value_or.

Meine persönliche optional verwendete emplace Syntax für value_or - wenn diejenige, die Sie hat verwenden, dass dann .value_or(throw_if_empty{}), wo throw_if_empty ein operator T() hat, die die optionalen leer Fehler auslöst.

+1

Irgendwann würde das optionale Ausschließen irgendwo einen Fehler bedeuten, und eine Ausnahme wäre in Ordnung. Die Definition von 'T extract (optional && o)' gefällt mir eigentlich am meisten, und es ist ein wenig seltsam, dass es dafür keinen Standard gibt. –

+0

@DmitryPanteleev Ah, ich habe '.value()' wirft vergessen. – Yakk

+0

Wie es in einem anderen Kommentar gezeigt wurde, ist dies nicht-optional-nur-Problem, so dass 'copy_of' könnte in der Tat nützlich sein. 'throw_if_empty' ist cool, aber es ist vielleicht nicht klar für jemanden neu, warum wird stattdessen' .value() 'verwendet –