Diese Antwort enthält ein Code-Snippet wie folgt:
%Vor%Es ist wirklich kompiliert und funktioniert ( zumindest auf Ideone ).
Also, wie wird der Typ in diesem Fall abgeleitet?
Ist die nächste Zeile wirklich nach C ++ 11 Standard erlaubt?
%Vor%Ich warf einen kurzen Blick darauf, und es sieht nicht gültig aus. Ist das in diesem Fall falsch?
Alle Beispiele im c ++ 11 Standard sind so, dass sie alle nur einen Typ im declltype haben:
%Vor%ein anderes Beispiel:
%Vor%und ein anderes
%Vor%Sie haben alle nur einen Parameter in decltype. Wie kommt es, dass der Top-Code zwei Parameter (getrennt durch ein Komma) enthält?
Ich habe ein anderes Beispiel erstellt (das nicht kompiliert werden kann):
%Vor% Selbst wenn die Zeile f(v,ops);
entfernt wird, wird der Rückgabetyp der Template-Funktion f
auf void ausgewertet.
decltype( bool( fun(v[0] ) ), void() )
verwendet den Kommaoperator .
Brechen Sie es auf,
%Vor%besteht aus zwei Ausdrücken; der erste
%Vor%wird ausgewertet 1 und verworfen, was dem gesamten Ausdruck den Wert
gibt %Vor% was ein Wert 2 vom Typ void
ist.
decltype
ergibt dann den Typ des Ausdrucks, der wie oben void
ist.
Der Grund für die Verwendung des Kommaoperators besteht darin, sicherzustellen, dass der gesamte Ausdruck nur dann gültig ist, wenn der erste Unterausdruck gültig ist. Dies liegt daran, dass es in SFINAE verwendet wird, um es von der Substitutionsüberlegung auszuschließen, wenn der erste Unterausdruck ungültig ist.
Das funktioniert, weil decltype
zwar syntaktisch wie eine Funktion aussieht, aber tatsächlich ein Sprachkonstrukt ist, das (wie sizeof
) für ein einzelnes Argument definiert ist. Es könnte klarer sein, das Komma-Operator-Argument in Klammern zu setzen:
bool( fun(v[0] ) )
wird nicht tatsächlich ausgewertet, da wir uns in einem nicht evaluierten Kontext befinden ( decltype
, ähnlich wie sizeof
). Was hier von Bedeutung ist, ist, dass ausgewertet würde, wenn der Ausdruck als Ganzes ausgewertet würde, so dass der ganze Ausdruck ungültig ist, wenn der Teilausdruck ungültig ist. void()
ist nicht wirklich ein Wert, sondern verhält sich wie ein Wert im Kontext des Kommaoperators und decltype
. decltype
liefert den Typ des Ausdrucks zwischen den Klammern, ohne ihn tatsächlich zu bewerten (behalte das für die nächsten Teile im Hinterkopf).
Der Operator ,
wertet das linke Argument / den Ausdruck aus, wirft das Ergebnis weg, wertet das richtige Argument aus und liefert das Ergebnis. Daher wird der Rückgabetyp void
.
Für den bool(fun(v[0]))
-Teil ist es ziemlich einfach. bool(f(...))
erstellt ein temporäres Bool aus dem Ergebnis des Aufrufs von f
. Wenn der Rückgabetyp von f
nicht in bool
konvertiert werden kann, wird ein Fehler ausgelöst, der zu SFINAE führt, da er sich in decltype
befindet (dies wird "Ausdruck SFINAE" ).
f(v[0])
übergibt den Rückgabewert von v[0]
an f
vom Typ T&
. Wenn f
keinen Parameter hat, in den T&
konvertiert werden kann, oder mehr / weniger Parameter akzeptiert, löst dies einen Fehler aus und führt wiederum zu SFINAE aus dem gleichen Grund wie oben.
(Das Gleiche würde passieren, wenn std::vector
operator[]
nicht unterstützt.)