14

C++ Standard Abschnitt 8.3.6.4 sagt, dassWarum kann das Standardargument später nicht in den Vorlagenfunktionen hinzugefügt werden?

Für Nicht-Template-Funktionen, Standardargumente später Erklärungen einer Funktion im gleichen Umfang aufgenommen in werden können. [...]

Aber meine Frage ist, warum es für Vorlagenfunktionen nicht erlaubt ist? Was ist der Grund dafür, das Hinzufügen von Standardargumenten in späteren Deklarationen im selben Gültigkeitsbereich für Vorlagenfunktionen nicht zuzulassen?

Betrachten Sie dieses Programm, das gut kompiliert. (Non Template-Funktion) (siehe Live-Demo here.)

#include <iostream> 

int f(int a,int b,int c=3); 
int f(int a,int b=9,int c); // default argument in middle, ok allowed 

int main() 
{ 
    f(3); 
    f(3,6); 
    f(3,6,9); 
    return 0; 
} 

int f(int a,int b,int c) 
{ 
    std::cout<<a<<' '<<b<<' '<<c<<'\n'; 
    return 0; 
} 

Aber nach nicht in der Zusammenstellung. (Template-Funktion) (siehe Live-Demo here.)

#include <iostream> 

template <typename T> 
void f(T a,int b,int c=3); 
template <typename T> 
void f(T a,int b=9,int c); // compiler error why??? 

int main() 
{ 
    f(3); 
    f(3,6); 
    f(3,6,9); 
    return 0; 
} 

template <typename T> 
void f(T a,int b,int c) 
{ 
    std::cout<<a<<' '<<b<<' '<<c<<'\n'; 
} 
+2

Fehlende 'Vorlage '? – LogicStuff

+0

Ist das nicht weniger * Addition * und mehr * Neudefinition * von Standardargumenten? – jaggedSpire

+2

[Hier ist] (http://coliru.stacked-crooked.com/a/39117b9aa49c90a4) ein fast kompilierendes Beispiel – jaggedSpire

Antwort

9

Dies ist eine historische Einschränkung, die relativ früh im Standardisierungsprozess hinzugefügt wurde (in C++ 98, aber nicht im ARM).

Ich erinnere mich nicht an den genauen Grund (und auch nicht mein Kollege, der fast sicher war, als die Entscheidung getroffen wurde). Wie auch immer, ich habe eine Vermutung ...

Damals instanziierten alle Compiler die Templates, indem sie die Token durch das Parsen wiederholten. Einige analysieren überhaupt keine Vorlagen. Bedenken Sie:

template<class T> struct S { 
    T f(T); // (1) 
}; 
template<class T> T S<T>::f(T p = 42) { return p; } // (2) 
S<int> s; // Causes the "real" parsing of (1), but not (2). 
int r = s.f(); // (3) 

Bei Aufruf der Lösung (3), ältere Compiler daher oft nur Zugriff auf die instanziiert Erklärung hatte (1), während (2) wurde noch nicht wirklich analysiert (nur Token-gepuffert). Daher war diesen Compilern das hinzugefügte Standardargument in (3) nicht bekannt.

Ist verdächtige Vorsicht angebracht, beschließt das Komitee daher, generelle Standardargumente in Templates generell zu verbieten.

Diese Einschränkung ist wahrscheinlich heute weniger (technisch) gerechtfertigt, da andere Standardanforderungen seither dazu geführt haben, Vorlagen in ihrer generischen Form zu analysieren (obwohl MSVC dies beispielsweise immer noch nicht tut).Allerdings ist es immer noch ein wenig mühsam zu implementieren, da Standardargumente möglicherweise in verschiedenen Kontexten instanziiert werden müssen.

+0

V: Was bedeutet (2) nur Token gepuffert? – Destructor

+4

Ich kann nicht glauben, dass diese Frage von Template-Experte und Autor von C++ - Vorlagen der komplette Leitfaden beantwortet wurde: David Vandevoorde – Destructor

+1

Re. "Token gepuffert" ... Einige Compiler (MSVC, EDG-basierte Compiler, Pre-3.4 GCC und die meisten älteren Compiler wie Cfront) behandeln Vorlagen, indem sie die Token, aus denen sie bestehen, "puffern". Zur Instanziierungszeit werden diese Token dann durch den Parser "wiederholt", außer dass die Template-Parameter-Token durch das entsprechende Template-Argument ersetzt werden. Eine Vorlage könnte also in einem Zustand "nur Token gepuffert; nicht geparst" sein. –

-6

Weil es im Grunde unmöglich ist.

Um Ihr Ziel zu erreichen, muss der Compiler eine Funktion implementieren, die bei zwei Template-Funktionen zurückgibt, ob sie die gleiche Funktion haben oder nicht. Das Problem ist, dass diese Funktion nicht ausführbar ist.

Für reguläre Nicht-Template-Funktionen ist dies eine schreckliche Idee, aber immer noch machbar, weil Sie nur die Argumenttypen und Arbeit erledigt haben müssen.

Leider, für Vorlagenfunktionen, wird dies ... schwieriger. Bedenken Sie:

template<typename T> void f(T t); 
template<typename U> std::enable_if_t<std::is_same<U, int>::value> f(U u = U()); 

Sie können sehen, dass sie wahrscheinlich die gleiche Funktion erklären, wennT ist int. Sonst nicht. Es gibt problematischere Interaktionen mit Standardvorlagenargumenten und ähnlichen Dingen, aber kurz gesagt, dies wäre für Vorlagen nicht entscheidbar.

+8

Der Compiler * bereits * muss Deklarationsabgleich durchführen; Sie dürfen die gleiche Funktionsvorlage mehrfach deklarieren. –

+0

@ T.C .: Das erfordert nicht wirklich die Übereinstimmung mit der Deklaration. – Puppy

+0

* "Es gibt problematischere Interaktionen mit Standardschablonenargumenten und ähnlichen Dingen" * AFAIK, Sie können Standardschablonenargumente zu einer späteren Wiederdeklaration einer Funktionsschablone hinzufügen. Ist das was du anspielst? Wenn ja, warum ist dieser Fall anders? – dyp

Verwandte Themen