2015-08-24 10 views
11

ho guardato un paio di discussioni legate overflow dello stack, come This case of template function overloading eludes my understandingPerché è illegale per le funzioni non basate su modelli avere lo stesso nome e argomenti ma tipi di ritorno diversi? (Ma legale per le funzioni del modello?)

e

Function overloading by return type?

ma nessuno dei due sembra darmi esattamente la risposta che sto cercando, almeno non in un modo che è stato facile da interpretare.

La mia domanda si riduce a questo: perché, sia da un design e punto di vista tecnico, è legale per fare questo:

#include <iostream> 

using namespace std; 

template<class T> 
void func(){ 
    cout << "Compiler inferred from void return value!\n"; 
} 

template<class T> 
int func(){ 
    cout << "Compiler inferred from int return value!\n"; 
    return 0; 
} 

int main(){ 
    void (*thisFunc)()=func<int>; 
    int (*thatFunc)()=func<int>; 
    thisFunc(); 
    thatFunc(); 
} 

Ma non questa:

#include <iostream> 

using namespace std; 

void func(){ 
    cout << "You won't see this because it won't compile!\n"; 
} 

int func(){ 
    cout << "Nor this one!\n"; 
    return 0; 
} 

int main(){ 
    void (*thisFunc)()=func; 
    int (*thatFunc)()=func; 
    thisFunc(); 
    thatFunc(); 
} 

Vale la pena ricordare che il primo esempio non verrà compilato se non fornisco esplicitamente un parametro template arbitrario durante l'inizializzazione di thisFunc e thatFunc. L'unica altra differenza tra i due è che il primo ha una funzione templata da un tipo che è completamente immateriale, tranne che a quanto pare mi permette di sovraccaricare il tipo restituito. Il compilatore è persino in grado di fare una deduzione in quel caso su quale funzione chiamare, rendendo l'illegalità dell'overload delle funzioni restituendo il tipo in C++ in qualche modo sconcertante. In ogni caso, è un trucco pulito, immagino.

EDIT: La cosa che mi preoccupa di più è l'incoerenza: Vorrei pensare molto a lungo e duramente prima che io sinceramente considerato sovraccarico per tipo di ritorno, ma se il "fissare" per qualcuno che vuole sovraccaricare dal tipo di ritorno è semplicemente aggiungere un parametro template senza senso o apparentemente avvolgere le funzioni all'interno di namespace, quindi penserei che sia C++ dovrebbe più o meno rigoroso su ciò che considera ambiguo. C'è una ragione convincente per cui template e namespace hanno bisogno di questa funzionalità per funzionare correttamente? Esiste un esempio di codice desiderabile che non potrebbe funzionare se, ad esempio, i modelli non consentissero di disambiguare il codice come nel mio esempio? Sto chiedendo da un punto di vista del design del linguaggio, non da un punto di vista della conformità del compilatore.

+0

Per modello, penso che sia per consentire SFINAE o restituire tipo. – Jarod42

+3

Non si sta veramente sovraccaricando sul tipo restituito, ma usando SFINAE quindi selezionare l'unica istanza di template possibile per ciascun puntatore di funzione. Quando si utilizza 'func ', in ogni dichiarazione c'è solo un modello in cui la sostituzione funziona, ma non è un errore perché l'altro non funzioni. È semplicemente ignorato. –

risposta

11

In generale non è valido: esiste un modo per sovraccaricare le funzioni non modello sul tipo restituito. Non è valido il modo in cui lo stai facendo.

namespace A { 
    void func() {} 
} 
namespace B { 
    int func() { return 0; } 
} 
using A::func; 
using B::func; 
int main(){ 
    void (*thisFunc)()=func; 
    int (*thatFunc)()=func; 
    thisFunc(); 
    thatFunc(); 
} 

Questo compila, collega e gira bene.

Poiché questo è valido ed è accettato dalle implementazioni reali, dovrebbe essere chiaro che non vi è alcun motivo tecnico per cui il codice non possa essere valido. Certo, richiederebbe alcune modifiche per denominare il manomissione, in quanto in genere le funzioni non di modello non hanno il tipo restituito nel nome storpiato, ma è facilmente fattibile.

Ciò che rimane è un motivo logico: sovraccaricare le funzioni non modello sul tipo restituito è quasi certamente un errore. Rende la funzione non modificabile in contesti normali, rende estremamente scarsamente diagnostici gli errori comuni (cambiando una dichiarazione in un posto e dimenticando l'altro posto), ha un uso estremamente limitato, quindi non farlo.

Problemi correlati