2012-12-03 13 views
5

Zauważyłem, że istnieje asymetria między podpisaniem używane do odróżnienia unikalne funkcje szablonów, a podpis używany do odróżnienia unikalne funkcje (w tym wystąpienia z funkcji szablonów).Jak rozróżniać szablony funkcji, które różnią się tylko typem zwrotnym?

W szczególności funkcji matrycy, różniące się jedynie ze względu na rodzaj powrotnej uważa się być unikalna, podczas gdy funkcje, które różnią się tylko przez rodzaj powrotnej uważa się za zbędne.

Dlatego mam odpowiednie pytanie na temat sposobu disambiguate między szablonami funkcyjnymi, które różnią się tylko przez typ zwracany, w momencie konkretyzacji:

#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? 
} 

W powyższym kodzie, konkretyzacją funkcji szablonu foo jest niejednoznaczna właśnie z powodu wspomnianej przeze mnie asymetrii. Obecność dwóch definicji funkcji szablon jest legalny, ale instancji jest nielegalne, nawet jeśli typ zwracany jest określony w tej samej linii kodu.

Zadaję to pytanie czysto teoretyczne dla celów uczenia się. Być może ten konstrukt kodu, w rzeczywistości, byłby oznaką złego projektu. Być może nigdy nie powstanie w prawdziwym życiu. Również mogę sobie wyobrazić różne sposoby przezwyciężenia tego problemu poprzez zmianę definicji szablonu (lub dokonywanie innych zmian).

Mimo to chciałbym się dowiedzieć, czy zachowując definicje szablonów bez zmian, możliwe jest ujednoznacznienie między tymi dwiema funkcjami szablonu w punkcie tworzenia.

Odpowiedz

6

Podczas korzystania z szablonów można w rzeczywistości rozróżnić dwa różne przeciążenia. To nie jest ładne, ale działa:

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

+1 , Nigdy o tym nie myślałem. Brzydki, ale poprawny. BTW, 'static_cast (foo) (d)' zmniejsza 1 znak :) – iammilind

+0

Idealny. Teraz moja wiara w szablony funkcjonalne została przywrócona. Zaczęłam się zastanawiać, dlaczego funkcyjne podpisy szablon to typ zwracany - jeżeli nie mogą one być ujednoznacznione kiedykolwiek. Ale, jak pokazuje twoja doskonała odpowiedź, mogą. –

1

Jeśli naprawdę trzeba mieć dwa szablony funkcyjne mają takie same nazwy, samą listę parametrów, ale różne rodzaje powrotne, nie masz wyboru, ale odróżnić dwa poprawiającym powrót wpisać parametr szablonu:

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

IIRC istnieje częściowa specjalizacja szablonu funkcja w C++ 11, chociaż nie mogłem znaleźć nic na ten temat w standardzie. Jeśli tak, to powinno działać:

//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'; 
} 

Albo w 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); 
} 

W obu przypadkach głównym będzie wyglądać następująco:

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