2012-02-16 11 views
11

Quello che segue è un pezzo di codice di test e sto confrontando il risultato della compilazione di questo con MSVC e Clang rispettivamente. L'output di ciascun compilatore è mostrato sotto. MSVC fa finta che la dichiarazione modello inutilizzata non esiste nemmeno. Clang produce un errore. La domanda è, quale compilatore è il più conforme standard qui?Clang vs MSVC: trattamento di prototipi di modelli di modello

Ho visto il codice di produzione legacy che si basa sul comportamento di MSVC e non sono sicuro se si può continuare a fare affidamento su o meno.

class S 
{ 
    struct P {}; 
}; 

template<typename T> 
S::P Bat(T); 

compila in modo pulito in MSVC10:

E:\clangbuild\bin\Release>cl /c /nologo test.cpp 
test.cpp 

genera un errore in Clang:

E:\clangbuild\bin\Release>clang++ test.cpp 
test.cpp:9:4: error: 'P' is a private member of 'S' 
S::P Bat(T); 
^
test.cpp:5:9: note: implicitly declared private here 
struct P {}; 
     ^
1 error generated. 
+2

Cosa, esattamente, pensi di "fare affidamento"? Il modello non può essere istanziato. –

+0

Il codice che sto osservando (ma non ha scritto) utilizza il fatto oscuro che MSVC consente al compilatore di compilare il modello non valido per applicare restrizioni sui tipi passati in altri modelli. Quando viene passato un tipo non valido, viene utilizzato un sovraccarico che utilizza questo modello, causando un errore di compilazione. – brendanw

+0

@brendanw: anche il front-end EDG non dà alcun errore. –

risposta

4

Ciò non riesce a causa della ricerca di nomi in due fasi in C++.

Nella fase uno, quando il modello viene analizzato inizialmente, molto prima che sia istanziato, il compilatore analizza il modello e cerca eventuali nomi non dipendenti. S::P è un nome non dipendente, quindi il compilatore tenta di cercarlo, ma fallisce perché è privato.

Nella fase 2, quando il modello viene istanziato, il compilatore cerca qualsiasi nome dipendente, che può variare da modello a modello.

Clang è abbastanza strettamente conforme alla ricerca del nome in due fasi. Tuttavia, MSVC ha un modello di parsing template che ritarda quasi ogni ricerca al tempo di istanziazione, che fa parte della fase 2. Questo ritardo è il motivo per cui il tuo esempio verrebbe compilato con MSVC (che non è conforme) e non in clang. Ecco un link con ulteriori informazioni:

The Dreaded Two-Phase Name Lookup

Inoltre, qui sezioni dallo standard C++ dove si descrive la ricerca in due fasi.

14.6.8:

Quando si cerca per la dichiarazione di un nome usato in una definizione di modello , le regole usuali di ricerca (3.4.1, 3.4.2) vengono utilizzati per nomi non dipendenti . La ricerca dei nomi che dipendono dai parametri del modello viene posticipata fino a quando non si conosce l'argomento del modello effettivo.

14.6.9:

Se il nome non dipende da un modello di parametri (come definito nella 14.6.2), una dichiarazione (o una serie di dichiarazioni) per tale nome deve essere nel campo di applicazione nel punto in cui il nome appare nella definizione del modello ; il nome è associato alla dichiarazione (o alle dichiarazioni) trovata in quel punto e questa associazione non è influenzata dalle dichiarazioni che sono visibili nel punto di istanziazione.

Poi la parte di 3.4 nomi di ricerca applicabile a voi:

Le regole di accesso (clausola 11) sono considerati solo una volta la ricerca dei nomi e risoluzione funzione di sovraccarico (se applicabile) sono riusciti. Solo dopo la ricerca del nome, la risoluzione di sovraccarico della funzione (se applicabile) e il controllo dell'accesso sono riusciti gli attributi introdotti dalla dichiarazione del nome utilizzata ulteriormente nell'elaborazione di espressioni (clausola 5).

È chiaro dalla lettura di queste parti che il programma è mal formato. L'unica cosa che gli stati standard dovrebbero essere rinviati fino alla creazione di istanze è la ricerca di un nome dipendente. I nomi non dipendenti passano attraverso la normale ricerca del nome, che include le regole di accesso.

+0

Hai radicato la causa (+1!), Tuttavia mi chiedo se entrambi siano conformi o meno. Sembra dannoso che lo Standard non specifichi se questo programma è mal formato o meno. –

+0

Il controllo dell'accesso non fa parte della ricerca del nome. MSVC (almeno per il 2010) esegue ricerche di nomi su tutti i nomi non dipendenti nelle dichiarazioni dei modelli; cambia S :: P in S :: A nell'esempio pubblicato e genererà un errore. – Gerald

+0

@Gerald MSVC controllerà se il nome esiste, ma la risoluzione dei nomi e il controllo dell'accesso sono parte della ricerca del nome. Vedi: http://stackoverflow.com/a/6273465/375343 –

3

Il compilatore è veramente solo necessario per verificare la presenza di qualsiasi sintassi errata delle dichiarazioni di modello non istanziati. Qualsiasi ulteriore valutazione semantica deve essere eseguita solo quando la funzione template viene istanziata.

Poiché S :: P è effettivamente un tipo che è valido per essere restituito da una funzione, entrambi sono ugualmente conformi.

+0

Quindi, è giusto dire che siamo semplicemente nel regno di un arbitrario livello di controllo degli errori come deciso dall'autore del compilatore e indefinito dallo standard? – brendanw

+0

@Gerald Il problema è: dove leggi questo nello standard? Ho cercato un'ora ora, senza successo. – Klaim

+0

@ Brendanw - sì. Per quanto riguarda lo standard C++, questa funzione non esiste. Ma i compilatori sono liberi di eseguire ulteriori verifiche degli errori. Tutto ciò che conta davvero per quanto riguarda lo standard è che quando il modello di funzione viene istanziato, non è valido. Nello scenario che descrivi nel tuo commento sotto la tua domanda, il modello di funzione viene implicitamente dichiarato quando un tipo non valido viene passato ad un altro modello, il che si traduce in un errore. Questo è un comportamento conforme agli standard, il resto dipende dal compilatore. – Gerald

Problemi correlati