2015-07-13 5 views
8

Auf gcc 4.9.0:die Adresse einer überladenen Funktionsvorlage zu nehmen ist möglich, manchmal

#include <iostream> 
#include <map> 

struct A 
{ 
    typedef int type; 
}; 

template<typename T> void foo(T*) { std::cout << "a" << std::endl; } 
template<typename T> void foo(typename T::type*) { std::cout << "b" << std::endl; } 

template<typename T> 
struct identity 
{ 
    typedef T type; 
}; 

template<typename T> void bar(T*) { std::cout << "a" << std::endl; } 
template<typename T> void bar(typename identity<T>::type*) { std::cout << "b" << std::endl; } 

int main() 
{ 
    //auto f = foo<A>; // ambiguous 
    foo<A>(0); // prints "b", as the second overload is more specific 

    auto b = bar<A>; // fine 
    bar<A>(0); // prints "b", as the second overload is more specific (?) 
    b(0); // prints "b" 

    return 0; 
} 

Jeder Hinweis auf, warum die Adresse kann, im zweiten Fall getroffen werden?

+0

Clang lehnt beide Fälle ab. –

+0

g ++ 4.9.0 scheint die zweite zu akzeptieren – gd1

+0

@ T.C., G ++ 4.9.2 kompiliert den Code und erzeugt eine Ausgabe, die der Beschreibung von OP entspricht. –

Antwort

3

Der Abzug für auto ist das gleiche wie Vorlage Abzug. Von [dcl.spec.auto]:

Wenn eine Variable deklariert ein Platzhalter-Typ unter Verwendung initialisiert wird, [...], die abgeleitete Rückgabetyp oder Variablentyp vom Typ seines initializer bestimmt ist. Wenn der Platzhalter der automatische Typspezifizierer ist, wird der abgeleitete Typ anhand der Regeln für die Ableitung von Vorlagenargumenten ermittelt. Wenn der Platzhalter autoTypspezifizierer, ist, wird der abgeleitete Typ anhand der Regeln für die Vorlageargumentableitung bestimmt.

Wenn wir also entweder:

auto f = foo<A>; 
auto b = bar<A>; 

Wir Typ Abzug durchführen, als ob wir genannt (TC Wortwahl leihen):

template <typename M> void meow(M); 
meow(foo<A>); 
meow(bar<A>); 

und unter Verwendung der abgeleiteten Geben Sie M als den Typ f bzw. b ein.

Aber nach [temp.deduct.type], Hervorhebung von mir:

Wenn ein Template-Parameter nur in nicht-abgeleitete Kontexten verwendet wird und nicht explizit angegeben wird, nicht Vorlage Argument Abzug.

Die nicht abgeleiteten Kontexte sind:
- [...]
- Ein Funktionsparameter für das Argument Abzug nicht durchgeführt werden kann, weil die zugehörige Funktion Argument ist eine Funktion, oder eine Reihe von überladenen Funktionen (13.4) und eine oder mehrere der folgenden Bedingungen zutrifft:
        - mehr als eine Funktion übereinstimmt, die Funktion Parametertyp (was zu einer mehrdeutigen Abzug), oder
        - keine Funktion entspricht die Funktion Parametertyp oder
        - der Satz von Funktionen als Argument geliefert enthält eine oder mehr Funktionsschablonen.
- [...]

In beiden Fällen sind das Argument, eine Reihe von überladenen Funktionen ist, die eine oder mehr Funktionsschablonen enthalten -, die einen nicht-abgeleitete Kontext macht, so Template-Argument Abzug versagt. Somit ist clang korrekt, wenn es beide Initialisierungen zurückweist.

+0

Das ist schwierig. Ich bin geneigt zu denken, dass [temp.deduct.type]/5.5.1 es zu einem nicht-abgeleiteten Kontext macht, was bedeutet, dass der "automatische" Abzug in beiden Fällen fehlschlagen sollte. –

+0

@ gd1 Für eine gründlichere Antwort auf Teilbestellung, überprüfen Sie [Antwort von Columbo hier] (http://Stackoverflow.com/a/31051322/2069064) – Barry

+0

@Barry Ich spreche nicht über den Abzug für 'bar' (es gibt natürlich keinen Abzug dort), ich spreche über den Abzug für 'auto', was ist, als ob du 'template void miau (M); miauen (bar ); 'und deduzieren' M'. –