2013-08-29 7 views
8

Ho giocato con la deduzione del tipo di ritorno supportata in g ++ con -std = C++ 1y.
Se prototipi una funzione con un tipo di ritorno esplicito, e poi successivamente si tenta di definire la funzione con il tipo di ritorno deduzione, il compilatore si lamenta di un ambiguo vecchia dichiarazione:Deduzione del tipo di ritorno con un prototipo esplicito in C++

std::string some_function(); 
... 
auto some_function(){ return std::string{"FOO"}; } //fails to compile 

C'è un buon motivo per cui questo doesn funziona?
La mia motivazione per l'utilizzo della deduzione del tipo restituito nella definizione è di mantenere il codice pulito, ma voglio un tipo esplicito nel prototipo per motivi autodocumentanti. Raccomandazioni sulle migliori pratiche per quando e quando non usare la deduzione del tipo restituito sarebbero apprezzate :)

Per essere più chiari, vorrei rispondere a:
1. Si tratta di un errore di implementazione nel compilatore? (Sono abbastanza sicuro che non lo sia)
2. Questo tipo di detrazione può essere fatto, ma non è consentito dalla proposta allo standard? Se è così, perché no?
3. Se questo è veramente ambiguo, quali sono alcuni esempi in cui la deduzione del tipo e il tentativo di associarlo a una dichiarazione esplicita in avanti potrebbero metterti nei guai?
4. Esistono problemi specifici di implementazione più approfonditi?
5. È semplicemente una svista?

+0

Per quando utilizzarlo, vedere [la mia domanda precedente] (http://stackoverflow.com/questions/15737223/when-should-i-use-c1y-automatic-return-type-deduction). – chris

+0

L'ho trovato nella [proposta] (http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3386.html): 'auto f(); // il tipo di ritorno è sconosciuto auto f() {return 42; } // return type is int auto f(); // redeclaration int f(); // errore, dichiara una funzione diversa ». Fammi controllare N3690. – chris

+0

Ah, N3690 ha lo stesso errore *, non può essere sovraccaricato con auto f() *. Non riesco a trovare dove lo dice, ma lo stai sovraccaricando invece di definirlo. – chris

risposta

6

E 'a causa di come le tabelle di funzioni e funzioni sovraccaricate lavorano in C++.

Quando il compilatore legge il tuo std::string some_function(); crea un punto perché faccia riferimento nel file binario e dice se "questa funzione viene mai chiamata salto in questo punto".

così abbiamo una vtable che assomiglia a questo ...

(Address offset) (Symbol) 
0x????????  std::string somefunction(); 

Ora che arrivi al auto some_function() {...}. Normalmente dovrebbe prima cercare nella tabella delle funzioni se auto somefunction(); esiste nella tabella o qualche variazione, ma il compilatore rileva che questa è un'implementazione e ha la parola chiave auto in modo da ridurre l'entropia che scrive *blank* some_function(); nella tabella delle funzioni e legami per risolvere il tipo di ritorno.

Ora la tabella funzione assomiglia a questo ...

(Address offset) (Symbol) 
0x????????  std::string somefunction(); 
0x????????  ????? somefunction(); 

Così sbuffa lungo la compilazione di codice in binario quando verifica il tipo di ritorno che in questo caso è std::string. Il compilatore ora sa quale sia il tipo restituito, quindi va alla tabella delle funzioni e cambia std::string somefunction();.

Ora la tabella funzione assomiglia a questo ...

(Address offset) (Symbol) 
0x????????  std::string somefunction(); 
0x????????  std::string somefunction(); 

Ora il compilatore va avanti e continua a compilare la funzione. Una volta fatto, torna indietro e finisce il vtable solo per scoprire che lo stesso simbolo è lì due volte. Ora è ambiguo a quale simbolo ci riferiamo anche noi.

Quindi qual è la ragione di questo?

Non sicuro al 100% ma i vtables vengono eseguiti molto prima che il codice venga elaborato abbastanza da consentire la creazione del tipo di detrazione. Quindi l'unica opzione con cui il compilatore deve lavorare in quel momento è semplicemente pensare che sia un nuovo simbolo. È solo qualcosa che ho notato guardando tabelle di simboli tutto il giorno e scrivendo il mio compilatore C++ 11.

Tuttavia, non posso in alcun modo parlare per altri compilatori in cui vengono introdotte molte ottimizzazioni e altri passaggi, io lavoro solo con le ossa nude, tuttavia questa è la mia comprensione dello standard.

Un'ultima cosa del tipo è completamente arbitraria. Non importa nemmeno se non corrispondono al momento della detrazione. Non arriva mai così lontano. Il problema è che ci sono due simboli uguali nella tabella e non è possibile sovraccaricare i tipi restituiti.

+0

Se sbaglio e non funziona per un altro motivo oltre a questo mi piacerebbe sapere. Mi aiuterebbe a creare compilatori migliori in futuro. –

-3

è necessario farlo come:

auto some_function() -> decltype(std::string) { return std::string{"FOO"}; } 

per ulteriori informazioni guardare in http://en.wikipedia.org/wiki/C%2B%2B11 -> funzione alternativa sintassi

+4

Questo vale solo per C++ 11, non C++ 1y, e 'decltype' non dovrebbe essere lì. – chris

+0

non è C++ 1y un aggiornamento a C++ 11, che dovrebbe contenere tutte le cose di C++ 11? –

+1

auto some_function() -> std :: string andrebbe bene ma questo non affronta la mia domanda poiché mi chiedo perché la deduzione del tipo restituito non funzioni con un prototipo tipizzato esplicitamente, mentre questa sarebbe una definizione tipizzata esplicitamente. –

Problemi correlati