2013-04-24 10 views
7

Nota: ho già cercato here e non penso che la risposta sia corretta.Istanza implicita dei modelli di funzione quando si prende il proprio indirizzo

Quali sono le regole che regolano l'istanziazione implicita delle funzioni quando si prendono i loro indirizzi? 14.7.1/9 di n3242 dice questo:

Un'implementazione non deve implicitamente un'istanza di un modello di funzione, un modello di elemento, una funzione di membro non virtuale, una classe membro, o un membro di dati statici di un modello di classe ciò non richiede istanziazione.

Ora, non è certamente necessario avere una definizione di funzione per prendere il suo indirizzo. Possiamo prendere l'indirizzo delle funzioni dichiarate in avanti e averle definite in una diversa unità di traduzione.

Stando così le cose, non so quando sarebbe necessario. Tuttavia, i compilatori sembrano avere una propria idea. Test su GCC e VC, ecco alcuni esempi:

template <typename T> void CallBanana() { T::Banana(); } 
template <typename T> void CallUnimpl(); 

template <typename T> 
struct S { 
    static void CallBanana() { T::Banana(); } 
    static void CallOrange() { T::Orange(); } 
    static void CallUnimpl(); 
}; 

struct B { static void Banana() {} }; 

int main() { 
    (void)(&CallBanana<void>); // 1 
    (void)(&CallUnimpl<void>); // 2 
    (void)(&S<void>::CallBanana); // 3 
    (void)(&S<void>::CallOrange); // 4 
    (void)(&S<void>::CallUnimpl); // 5 
    (void)(&S<B>::CallBanana); // 6 
} 

Questi dovrebbero essere commentate in uno alla volta per vedere gli effetti.

GCC 4.7 tested here si lamenterà di 1, 3 e 4. Quindi crea un'istanza di tutte le definizioni se esistono.

VC 2010 (nessun test on-line, sorry) un'istanza di 3 e 4, ma non istanziare 1.

Clang 3.0 tested here ha lo stesso comportamento di VC 2010.

No compilatore si lamenta circa 2 o 5, che mi aspetterei. Mi aspetterei che non riesca a collegare se ho effettivamente usato quei puntatori però.

Su tutti i compilatori, 6 compila. Mi aspetto questo, ma è inteso a dimostrare che l'intero modello di classe non è istanziato (come sostenuto nella risposta a quell'altra domanda) solo perché prendo l'indirizzo di una singola funzione. Se l'intero modello è stato istanziato, allora S :: CallOrange non dovrebbe essere compilato, perché B non contiene una funzione arancione.

Quindi mi chiedo se qualcuno ha una risposta definitiva su quale dovrebbe essere il comportamento corretto. Lo standard sembra affermare che nessuna funzione debba essere istanziata, tuttavia tre popolari compilatori istanziano in alcuni casi, ma differiscono l'uno dall'altro.

+0

Non sono affatto d'accordo, per quanto posso vedere lo standard richiede che la funzione venga istanziata quando viene preso il suo indirizzo e vengono presi tutti e 6 gli indirizzi. Se la funzione non può essere istanziata (1, 3 e 4), verrà generato un errore di compilazione. Quindi direi che 2, 5 e 6 dovrebbero essere istanziati; e dal momento che il loro indirizzo è preso (se lanci a 'void' è irrilevante) la loro assenza dovrebbe provocare un errore del linker (se non ottimizzato). –

+0

"per quanto posso vedere" - dove? Sezione e paragrafo, per favore. I lanci a vuoto sono semplicemente per evitare avvisi su espressioni usate come affermazioni, non correlate a ciò che sto facendo. – Fuz

+0

Se avessi la sezione e il paragrafo, sarebbe una risposta;) Credo che rientri nel caso odr-used. –

risposta

6

A definizione di una funzione richiesta se si prende il suo indirizzo (all'interno di un contesto valutato).

Ovviamente la definizione può essere fornita in un'unità di traduzione separata, ma ciò non cambia il fatto che sia necessaria una definizione.

Se è necessaria solo una funzione membro, ciò non implica che anche le altre funzioni membro siano istanziate.

Se il modello di funzione non è definito, non può essere istanziato in modo implicito. Deve quindi essere esplicitamente istanziato in un'altra unità di traduzione. Affidarsi a un'istanza implicita in un'altra unità di traduzione non è consentita (ma non è richiesta alcuna diagnostica).

+0

14p6 per quell'ultimo punto, penso. Per quanto riguarda il punto principale, non è necessario che una definizione di funzione sia visibile anche per essere * chiamata *, ma lo standard intende chiaramente che una chiamata determina l'istanziazione di una definizione del modello di funzione; prendere un puntatore non è diverso. – ecatmur

+0

14.7.1/2 dice "la specializzazione del modello di funzione è implicitamente istanziata quando la specializzazione viene referenziata in un contesto che richiede l'esistenza di una definizione di funzione". È un po 'lanoso (nella mia mente), ma immagino che questo possa essere interpretato in questo modo. In tal caso, Clang è carente non istanziando i modelli di funzione non membri? Sono meno sorpreso dal fatto che VC abbia sbagliato. :) – Fuz

+0

Ho contrassegnato questo come la risposta accettata, anche se sarei più felice se ci fosse una spiegazione più chiara di "richiede una definizione della funzione di esistere" per vedere se il comportamento di VC e Clang è sancito dallo standard. – Fuz

0

L'istanziazione deve essere eseguita, poiché l'espansione del modello potrebbe non risultare in un codice ben formato.

Infatti, l'istanziazione potrebbe anche non risultare in un prototipo valido (questo errore si qualifica come "non un fallimento").

(Quando SFINAE è coinvolto l'indirizzo effettivo preso potrebbe ignorare diversi in precedenza i candidati nella ordinamento parziale (perché Sostituzione fallimento non è un errore), prima che il candidato reale è selezionata per prendere l'indirizzo di.)

+0

Penso che questo non sia corretto. 14.7.1/8 dice "Se un modello di funzione o una specializzazione del modello di funzione membro viene utilizzata in un modo che implica una risoluzione di sovraccarico, una dichiarazione della specializzazione viene implicitamente creata". Nota: la * dichiarazione * è istanziata, non la definizione. – Fuz

Problemi correlati