2017-11-24 5 views
4

wird dies durch beispielsweise inspiriert von cppreferenceWie wird in diesem Beispiel std :: variant wertlos_bis_exception?

struct S { 
    operator int() { throw 42; } 
}; 


int main(){ 
    variant<float, int> v{12.f}; // OK 
    cout << std::boolalpha << v.valueless_by_exception() << "\n"; 
    try{ 
     v.emplace<1>(S()); // v may be valueless 
    } 
    catch(...){ 
    } 
    cout << std::boolalpha << v.valueless_by_exception() << "\n"; 
} 

Zum einen Compiler habe ich versucht, es

false, true

Sinn gibt, dass emplace die Variante valueless

werden verursacht

Was ich nicht verstehe ist, wie das passiert ist. Insbesondere verstehe ich nicht warum emplace überhaupt aufgerufen wird, ich würde erwarten, dass das Programm es nicht einmal seit der Konvertierung von S zu int Argument wirft.

+2

Konvertierung erfolgt innerhalb der 'emplace' Funktion, nicht in' main'. – Jarod42

Antwort

5

Notiere die Signatur für den jeweiligen std::variant::emplace Überlastung:

template <size_t I, class... Args> 
std::variant_alternative_t<I, variant>& emplace(Args&&... args); 

Es eine Packung Forwarding Referenzen nimmt. Dies bedeutet, dass der Konvertierungsoperator von S zu int bei der Auswertung der Funktionsargumente nicht aufgerufen wird; Es heißt im Körper von emplace. Da der Versuch fehlschlug, die int an Ort und Stelle zu konstruieren, wird die Variante ausnahmslos wertlos gemacht. Es könnte vielleicht möglich sein, variant so zu implementieren, dass für trivial bewegliche Typen der alte Wert gespeichert wird, bevor die Konstruktion versucht wird, und dann wiederhergestellt wird, wenn er fehlschlägt, aber ich bin mir nicht sicher, ob er in die passt verschiedene Einschränkungen für die Implementierung des Typs durch den Standard.

+1

In Bezug auf Design-Entscheidungen hier ist ein schöner Link für diese https://cbeck88.github.io/strict-variant/strict_variant/overview/design.html – NoSenseEtAl

+0

"Ich bin mir nicht sicher, ob es mit den verschiedenen Einschränkungen des Typs passt Umsetzung durch den Standard. " Ich habe diese Erklärung auf den Lib-Reflektoren gehört, um zu erklären, warum die 'emplace'-Formulierung besagt, dass die Variante" * keinen Wert halten könnte ", wenn die Initialisierung ausgelöst wird, aber es mir schwer fällt" den aktuell enthaltenen Wert zu löschen wenn 'wertloses_von_exception()' 'false' ist." as "erstellt eine Kopie des aktuell enthaltenen Wertes, um später in die' Variante' der Ausnahme einzufügen. " – Casey

+2

Boost hat die nie leere Garantie ... in diesem Fall glaube ich, dass 'boost :: variant' den alten Wert von' float' speichert, da er nicht kopiert/zurückversetzt werden kann. In dem seltenen Fall, dass es keinen Weg gibt, irgendeinen Wert als "noexcept" wiederherzustellen, verwenden sie eine Heap-Zuweisung und "Doppelpufferung". '' '' '' anstelle von "noweless_by_exception" wurde für "std :: variant" gewählt, und zwar aus Performance-Gründen und weil 'boost :: variant's Fehlermodi sehr überraschend sein können. –

Verwandte Themen