2012-12-03 18 views
5

Ich habe festgestellt, dass es eine Asymmetrie zwischen der Signatur gibt, die zur Unterscheidung eindeutiger Vorlagenfunktionen verwendet wird, und der Signatur, die zur Unterscheidung eindeutiger Funktionen verwendet wird (einschließlich derjenigen, die aus Vorlagenfunktionen instanziiert werden).Wie können Funktionsschablonen, die sich nur durch den Rückgabetyp unterscheiden, disambiguiert werden?

Insbesondere Template-Funktionen, die sich nur durch den Rückgabetyp unterscheiden, werden als eindeutig betrachtet, während Funktionen, die sich nur durch den Rückgabetyp unterscheiden, als redundant betrachtet werden.

Daher habe ich eine entsprechende Frage, wie zwischen Funktionsschablonen, die nur von Rückgabetyp unterscheiden, an dem Punkt der Instanziierung eindeutig zu machen:

#include <iostream> 

template<typename T> 
long foo(T) 
{ 
    std::cout << "long" << std::endl; 
    return 0; 
} 

template<typename T> 
char foo(T) 
{ 
    std::cout << "char" << std::endl; 
    return '\0'; 
} 

int main() 
{ 
    double d = 0.0; 
    long n = foo(d); // <- Ambiguous: How to specify the template function to use? 
} 

In dem obigen Code, die Instanziierung der Schablonenfunktion foo ist mehrdeutig gerade wegen der Asymmetrie, die ich gerade erwähnt habe. Das Vorhandensein der beiden Vorlagenfunktionsdefinitionen ist zulässig, die Instanziierung ist jedoch unzulässig, obwohl der Rückgabetyp in derselben Codezeile angegeben ist.

Ich stelle diese Frage rein für theoretische Lernzwecke. Vielleicht wäre dieses Code-Konstrukt im wirklichen Leben ein Zeichen für schlechtes Design. Vielleicht würde es im wirklichen Leben nie entstehen. Ich kann mir auch verschiedene Möglichkeiten vorstellen, dieses Problem zu lösen, indem ich die Template-Definitionen ändere (oder andere Änderungen vornahm).

Dennoch würde ich gerne wissen, ob, unter Beibehaltung der Template-Definitionen, es möglich ist, zwischen diesen beiden Template-Funktionen zum Zeitpunkt der Instanziierung zu disambiguieren.

Antwort

6

Bei der Verwendung von Vorlagen können Sie tatsächlich die zwei verschiedenen Überladungen unterscheiden. Es ist nicht schön, aber funktioniert:

long n = static_cast<long(*)(double)>(&foo)(d); 
+1

+1 Hab 'nie darüber nachgedacht. Hässlich aber korrekt. BTW, 'static_cast (foo) (d)' reduziert 1 Zeichen :) – iammilind

+0

Perfekt. Jetzt ist mein Vertrauen in Funktionsvorlagen wiederhergestellt. Ich fing an, mich zu wundern, warum Funktionsschablonensignaturen Rückgabetyp enthalten - wenn sie nicht immer eindeutig sein können. Aber, wie Ihre ausgezeichnete Antwort zeigt, können sie. –

1

Wenn Sie wirklich zwei Funktionsschablonen die gleichen Namen, die gleiche Liste von Parametern, aber unterschiedliche Rückgabetypen aufweisen haben müssen, haben Sie keine andere Wahl, als unterscheiden, die beide durch die Herstellung von Rückkehr geben sie einen Template-Parameter:

template <typename R, typename T> 
R foo(T); 

IIRC gibt es Teilfunktion Template-Spezialisierung in C++ 11, obwohl ich nichts davon in der Standard finden konnten. Wenn ja, sollte diese Arbeit:

//partial function template specializations: C++11 only! 
template <typename T> 
long foo<long, T>(T) 
{ 
    std::cout << "long" << std::endl; 
    return 0; 
} 

template<typename T> 
char foo<char, T>(T) 
{ 
    std::cout << "char" << std::endl; 
    return '\0'; 
} 

Oder aber, in C++ 03:

template <typename R, typename T> 
struct FooImpl; 

template <typename T> 
struct FooImpl<long, T> 
{ 
    static long doIt(T) 
    { 
    std::cout << "long" << std::endl; 
    return 0; 
    } 
}; 

template <typename T> 
struct FooImpl<char, T> 
{ 
    static char doIt(T) 
    { 
    std::cout << "char" << std::endl; 
    return '\0'; 
    } 
}; 

template <typename R, typename T> 
R foo(T t) 
{ 
    return FooImpl<R, T>::doIt(t); 
} 

In beiden Fällen würde Ihre Haupt wie folgt aussehen:

int main() 
{ 
    double d = 0.0; 
    long n = foo<long>(d); // specify the return type only 
    auto c = foo<char>(n); 
} 
Verwandte Themen