2016-08-08 101 views
4
struct Value { 
    using a_type = int; 
    a_type f() { return 1; } 
}; 

template<typename T> 
struct Wrapper { 
    T t; 
    auto call_f() { return t.f(); } 
}; 

int main() { 
    Wrapper<Value> w; 
    Wrapper<int> w2; 
    w.call_f(); 
} 

Dies kompiliert in Clang und GCC. Wrapper<int> wird instanziiert, obwohl der Rückgabetyp Wrapper<int>::call_f() nicht abgeleitet werden kann (es gibt keine int::f()). Es schlägt nur fehl, wenn w2.call_f() aufgerufen wird.Template Instanziierung mit undefinierten Memberfunktion Rückgabetypen

Ist dieser Teil des C++ - Standards, und kann erwartet werden, dass er auf allen Compilern funktioniert?

Antwort

11

Ja, das ist Teil des C++ - Standards.

Die Regeln der Vorlageninstanziierung sind lang und komplex, aber die kurze Version besteht darin, dass eine Elementfunktion einer Vorlagenklasse nur bei Bedarf instanziiert wird. Wenn nichts es aufruft oder versucht, einen Zeiger darauf zu setzen, oder es explizit instanziiert (und wahrscheinlich ein paar andere Fälle, die ich vergesse), dann wird es nicht instanziiert und Ihr Code ist wohlgeformt.

Wie @dyp weist darauf hin, es ist nur die Erklärung der Elementfunktion, die instanziiert wird, wenn die Klassendefinition instantiiert wird ([temp.inst]/1), aber der Rückgabetyp Abzug wird nur ausgeführt, wenn die Funktion Definition ist instanziiert ([dcl.spec.auto]/12).

Dies ist äußerst hilfreich, um sowohl den Overhead von Vorlagen zu minimieren als auch den Typanforderungen zuzustimmen. Es ist diese Eigenschaft, die man so etwas tun können:

struct Foo { 
    //no default constructor 
    Foo(int); 
}; 

std::vector<Foo> foos; 

Einige std::vector Funktionen (resize, zum Beispiel) T erfordern default-konstruierbar zu sein, aber solange man Sie noch nicht über diese Funktionen aufrufen können andere Merkmale von std::vector.

2

Ja, es ist durch den Standard garantiert. Wrapper<T>::call_f() wird implizit nur beim Aufruf instanziiert.

$14.7.1/2 Implicit instantiation [temp.inst]:

Es sei denn, ein Mitglied einer Klasse-Vorlage oder ein Mitglied Vorlage wurde explizit instanziiert oder explizit spezialisiert, die Spezialisierung des Mitglieds implizit instanziiert wird, wenn die Spezialisierung in einem Kontext verwiesen wird, das erfordert die Mitgliedsdefinition zu existieren;

$14.7.1/8 Implicit instantiation [temp.inst]:

Eine Implementierung ist nicht implizit eine Funktionsvorlage, eine variable Schablone, ein Mitglied Vorlage instanziiert, eine nicht-virtuelle Member-Funktion, ein Mitglied der Klasse, ein statisches Datenelement einer Klasse Vorlage oder eine Unteranweisung einer constexpr if-Anweisung ([stmt.if]), sofern diese Instanziierung nicht erforderlich ist.