2016-07-12 10 views
37

Beachten Sie Folgendes:Warum funktioniert die automatische Rückgabetypabrechnung mit nicht vollständig definierten Typen?

template<typename Der> 
struct Base { 
    // NOTE: if I replace the decltype(...) below with auto, code compiles 
    decltype(&Der::operator()) getCallOperator() const { 
     return &Der::operator(); 
    } 
}; 

struct Foo : Base<Foo> { 
    double operator()(int, int) const { 
     return 0.0; 
    } 
}; 

int main() { 
    Foo f; 
    auto callOp = f.getCallOperator(); 
} 

ich eine Member-Funktion in CRTP Basisklasse mit einem Rückgabetyp je nach Unterzeichnung der operator() in der abgeleiteten Klasse erstellt werden soll. decltype(&Der::operator()) kann jedoch nicht kompiliert werden. Die Elementfunktion operator() in Foo ist nicht sichtbar. Ich nehme an, dass dies daran liegt, dass die Basisklassenvorlage instanziiert wird, bevor Foo vollständig definiert ist.

Überraschenderweise, wenn ich auto für den Rückgabetyp setzen kompiliert. Ich nahm an, dass auto würde den Compiler den Rückgabetyp vom Funktionskörper ableiten und fehlschlagen - weil der Körper den nicht vollständig definierten Foo-Typ verwendet.

Dieses Verhalten ist das gleiche für beide MSVC 2015,3 und Clang 3.8

Warum der Code nicht beginnen mit auto zu arbeiten? Ist Typ Abzug irgendwie "verzögern" die Instanziierung? Oder verwenden Sie einen anderen Kontext als einen handgeschriebenen Rückgabetypausdruck?

+5

Gute Frage. Upvoted. –

+0

Mögliches Duplikat von [CRTP und C++ 1y Rückgabetyp Abzug] (http://stackoverflow.com/questions/19892479/crtp-and-c1y-return-type-deduction) – Holt

+0

Es ist das gleiche Problem, aber Frage und Antwort Ansatz es aus einem etwas anderen Winkel. Hier haben wir "wie die automatische Ableitung ist anders", die verknüpfte Frage und ihre Antwort ist mehr über "wie kann ich den handschriftlichen Ausdruck arbeiten lassen". Obwohl es sich immer noch als Duplikat qualifizieren kann ... –

Antwort

24

Ihre Schätzung ist richtig. Ein abgeleiteter Rückgabetyp wird nicht tatsächlich abgeleitet, bis die Signatur der Funktion benötigt wird. Dies bedeutet, dass es im Zusammenhang mit dem Aufruf an getCallOperator abgeleitet wird, an welchem ​​Punkt Foo vollständig definiert ist.

Diese in 7.1.6.4p12 angegeben:

Rückgabetyp Abzug für eine Funktionsschablone mit einem Platzhalter in seinem deklarierten Typ tritt auf, wenn die Definition auch wenn die Funktion Körper enthält eine return-Anweisung mit einem instanziiert nicht typabhängiger Operand.