2012-12-03 6 views
5

Ho notato che esiste un'asimmetria tra la firma utilizzata per distinguere le funzioni del modello univoco e la firma utilizzata per distinguere le funzioni univoche (incluse quelle istanziate dalle funzioni del modello).Come disambiguare i modelli di funzioni che differiscono solo per il tipo restituito?

In particolare, le funzioni di modello che differiscono solo per tipo di ritorno sono considerate come univoche, mentre le funzioni che differiscono solo per il tipo di ritorno sono considerate ridondanti.

Pertanto, ho una corrispondente domanda su come disambiguare tra i modelli funzionali che differiscono solo per il tipo di ritorno, al punto di istanziazione:

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

Nel codice precedente, l'istanza della funzione template foo è ambiguo proprio per l'asimmetria che ho appena menzionato. La presenza delle due definizioni di funzioni del modello è legale, ma l'istanziazione è illegale, anche se il tipo di ritorno è specificato nella stessa riga di codice.

Sto facendo questa domanda esclusivamente per scopi di apprendimento teorico. Forse questo costrutto di codice, nella vita reale, sarebbe un segno di design scadente. Forse non si presenterebbe mai nella vita reale. Inoltre, posso immaginare diversi modi per superare questo problema modificando le definizioni dei modelli (o apportando altre modifiche).

Tuttavia, vorrei comunque sapere se, mantenendo invariate le definizioni del modello, è possibile disambiguare tra queste due funzioni del modello nel punto di creazione dell'istanza.

risposta

6

Quando si utilizzano i modelli è possibile disambiguare i due diversi sovraccarichi. Non è abbastanza, ma funziona:

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

+1 , Mai pensato a questo. Brutto ma corretto. BTW, 'static_cast (foo) (d)' riduce 1 carattere :) – iammilind

+0

Perfetto. Ora la mia fiducia nei modelli di funzioni viene ripristinata. Stavo cominciando a chiedermi perché le firme dei modelli di funzione includessero il tipo restituito - se non possono mai essere disambiguate. Ma, come rivela la tua eccellente risposta, possono farlo. –

1

Se davvero bisogno di avere due modelli di funzione con gli stessi nomi, stesso elenco di parametri, ma diversi tipi di ritorno, non hai scelta, ma differenziare i due facendo il ritorno digitare un parametro di modello:

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

IIRC non v'è parziale specializzazione modello di funzione in C++ 11, anche se non ho trovato nulla nella norma. Se c'è, questo dovrebbe funzionare:

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

Oppure, 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 entrambi i casi, il vostro principale sarebbe simile a questa:

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