0

Ich habe einen Fall, in dem Lookup und Überladungsauflösung anders verhält:Überlastung Auflösung, Namenssuche und Funktionszeiger

  • für benutzerdefinierte Klasse vs eingebauten Typen vs std :: string
  • für den direkten Aufruf vs Funktionszeiger Anruf

ich nicht, was genau Teile der Norm diese verschie rechtfertigen herausfinden kann Zensuren.

Betrachten Sie den folgenden C++ 11-Code:

#include <iostream> 
#include <string> 

using namespace std; 

struct Test1 {}; 
struct Test2 {}; 

template<typename T> 
int f(T t) { return 0; } 

int f(Test1 t) { return 10; } 
int f(int y) { return 20; } 

template<typename T> 
int use1() { return f(T()); } 

template<typename T> 
int use2() { auto fp = static_cast<int(*)(T)>(&f); return (*fp)(T()); } 

int f(Test2 t) { return 30; } 
int f(string s) { return 40; } 
int f(double y) { return 50; } 

int main() { 
    cout << "use1<float>: " << use1<float>() << endl; 
    cout << "use1<Test1>: " << use1<Test1>() << endl; 
    cout << "use1<int>: " << use1<int>() << endl; 
    cout << "use1<Test2>: " << use1<Test2>() << endl; 
    cout << "use1<string>: " << use1<string>() << endl; 
    cout << "use1<double>: " << use1<double>() << endl; 
    cout << endl; 
    cout << "use2<float>: " << use2<float>() << endl; 
    cout << "use2<Test1>: " << use2<Test1>() << endl; 
    cout << "use2<int>: " << use2<int>() << endl; 
    cout << "use2<Test2>: " << use2<Test2>() << endl; 
    cout << "use2<string>: " << use2<string>() << endl; 
    cout << "use2<double>: " << use2<double>() << endl; 
    return 0; 
} 

Ausgang ist (gleich mit g ++ 6.3 und Klirren ++ 5.0.0 Stamm):

use1<float>: 0 
use1<Test1>: 10 
use1<int>: 20 
use1<Test2>: 30 
use1<string>: 0 
use1<double>: 0 

use2<float>: 0 
use2<Test1>: 10 
use2<int>: 20 
use2<Test2>: 0 
use2<string>: 0 
use2<double>: 0 

Fragen :

  1. Warum unterscheidet sich use1<string> von use1<Test2>? Beide Typen werden "an der Spitze" deklariert, beide f() Überladungen werden am Ende deklariert.
  2. Warum unterscheidet sich use1<Test2> von use1<double>? Entsprechende f() - Überlastungen liegen auf benachbarten Linien, gibt es etwas Spezielles in der Behandlung von eingebauten Typen?
  3. Warum unterscheidet sich use1<Test2> von use2<Test2>? Der Typ eines in use2 funktionierenden Zeigers scheint mit dem aufrufenden Kontext in use1 übereinzustimmen.

Antwort

0

Zweiphasige Namenssuche. An dem Punkt, an dem use1 definiert ist, sind drei Überladungen von f über normales Nachschlagen sichtbar. Zum Zeitpunkt der Instanziierung können zusätzliche Überladungen gefunden werden - jedoch nur durch argumentabhängiges Nachschlagen. Test2 ist im globalen Namespace, daher wird f(Test2) von ADL gefunden; während string in Namespace std ist, und so f(string) (das ist natürlich nicht im Namespace std) wird nicht von ADL gefunden. double hat keine zugeordneten Namespaces und daher tritt ADL überhaupt nicht ein.

In use2 ist f kein abhängiger Name und daher wird die Suche in der zweiten Phase überhaupt nicht durchgeführt - nur Überlastungen, die am Definitionspunkt sichtbar sind, werden berücksichtigt.

+0

Danke! In Bezug auf use2: Gibt es einen Weg in use2 einen Funktionszeiger zu erhalten, der die Adresse der exakt gleichen Überladung von f() enthält, die in use1 aufgelöst wird? – salmin

+0

Ich kann mir keinen Weg vorstellen, einen Namen zu "verpfänden". Der Standard sieht nur die zweite Nachschlagephase vor, wenn der Name in einem direkten Funktionsaufruf verwendet wird, 'name (some_args)', und nicht in anderen Fällen, in denen eine Überladungsauflösung durchgeführt werden muss. –