1

C++ 14 Entwurf n4140 liestWas ist die Bewertungsstrategie (eifrig, faul, ...) von C++ Metafunktionen wie std :: conditional?

T wird

für template <class T> struct underlying_type ein Aufzählungstyp sein.

Wie schlimm ist es

std::conditional_t<std::is_enum<T>::value, std::underlying_type_t<T>, foo> 

zu schreiben, wenn T ein beliebiger Typ sein kann? Werde ich auf eine UB treten und der Compiler würde mein $ HOME löschen (weil Sprachanwälte sagen, "alles kann unter einer UB passieren")?

+2

UB passiert zur Laufzeit, Template-Funktionen wie diese erledigen ihre Arbeit zur Kompilierzeit. Wie für "wird es löschen $ HOME" siehe [Chandler's Gespräch] (https://www.youtube.com/watch?v=yG1OZ69H_-o) – Borgleader

+0

Dies ist Kompilierzeit Auswertung, keine Laufzeit. Sie werden hier nicht auf UB stoßen. – AndyG

+0

@Borgleader OK "wird die resultierende Binärdatei möglicherweise mein $ HOME löschen?" Eigentlich bin ich mir nicht einmal sicher, ob es ein UB zum Schreiben von 'std :: soundly_type_t ' gerade (ohne 'std :: conditional') gibt. Bedeutet" soll ", dass seine Verletzung zu einem schlecht geformten Programm führt? – nodakai

Antwort

4

Werde ich Schritt auf eine UB [...]

Technisch ja. Aber praktisch kompiliert es nicht nur für Nicht-Aufzählungstypen. Wenn Sie schreiben:

std::conditional_t<std::is_enum<T>::value, std::underlying_type_t<T>, foo>;  
              ^^^^^^^^^^^^^^^^^^^^^^^^^ 

Das Template-Parameter muss vor die conditional Vorlage ausgewertet werden instanziiert werden kann. Dies ist äquivalent zu allen Funktionsargumenten, die aufgerufen werden müssen, bevor der Rumpf der Funktion beginnt. Für nicht aufgezählte Typen ist underlying_type<T> unvollständig (sicher ist es im Standard als undefiniert angegeben, aber lasst uns vernünftig sein), also gibt es kein underlying_type_t. Daher schlägt die Instanziierung fehl.

Was müssen Sie tun, ist Verzögerung die Instanziierung in diesem Fall:

template <class T> struct tag { using type = T; }; 

typename std::conditional_t< 
    std::is_enum<T>::value, 
    std::underlying_type<T>, 
    tag<foo>>::type; 

Nun, unsere conditional statt der Auswahl Typen ist die Auswahl eines metafunction! underlying_type<T>::type wird nur instanziiert, wenn T eine Enumeration ist. Wir müssen außerdem foo umhüllen, um es in eine Metafunktion umzuwandeln.

Dies ist ein gemeinsames Muster und war eine besondere Sache in Boost.MPL eval_if genannt, die aussehen würde:

template <bool B, class T, class F> 
using eval_if_t = typename std::conditional_t<B, T, F>::type; 

Bitte beachte, dass wir mit beiden conditional_tund::type.

+0

OK, also C++ Metafunktionen verwenden eifrige Auswertung (wenn wir nicht Ihren "Tag" -Trick verwenden.) Ihr Beitrag ist sehr erziehend, aber ich denke, dass ich ein bisschen mehr Zeit brauche, um es zu begreifen. – nodakai

+0

@nodakai Denken Sie daran, wie - Template-Argumente sind Metafunktionen welche Funktion Argumente zu Funktionen sind. – Barry