2013-05-09 27 views
5

MODIFICA: Questo non è un bug, solo che non so di dependent name lookups in templated base classes (che MSVC "utilmente" risolve senza errori).Si tratta di un bug in GCC?


Ho scritto un'implementazione di funtore un po 'indietro e un semplice wrapper "Event" che lo utilizza. Compila bene in MSVC, ma GCC restituisce un errore su una variabile membro nella classe base, subscribers, non dichiarata; la modifica di subscribers a this->subscribers risolve il problema (!). Sembra che accada solo con il modello di template curiosamente ricorrente e con la specializzazione del modello parziale.

fonte semplificato (scusate per l'utilizzo modello spremere le meningi ...):

#include <vector> 

template<typename TEvent> 
struct EventBase 
{ 
protected: 
     std::vector<int> subscribers; 
}; 

template<typename TArg1 = void, typename TArg2 = void> 
struct Event : public EventBase<Event<TArg1, TArg2> > 
{ 
     void trigger(TArg1 arg1, TArg2 arg2) const 
     { 
       // Error on next line 
       auto it = subscribers.cbegin(); 
     } 
}; 

template<typename TArg1> 
struct Event<TArg1, void> : public EventBase<Event<TArg1> > 
{ 
     void trigger(TArg1 arg1) const 
     { 
       // Using `this` fixes error(?!) 
       auto it = this->subscribers.cbegin(); 
     } 
}; 

template<> 
struct Event<void, void> : public EventBase<Event<> > 
{ 
     void trigger() const 
     { 
       // No error here even without `this`, for some reason! 
       auto it = subscribers.cbegin(); 
     } 
}; 

int main() 
{ 
     return 0; 
} 

Perchè sono invocano un comportamento indefinito da qualche parte? La mia sintassi è in qualche modo sbagliata? Questo è davvero un bug in GCC? È forse un bug noto? Qualsiasi intuizione sarebbe apprezzata!

Ulteriori dettagli: compilato utilizzando g++ -std=c++11 main.cpp. Sto usando GCC versione 4.7.2. Messaggio di errore esatto:

main.cpp: In member function ‘void Event<TArg1, TArg2>::trigger(TArg1, TArg2) const’: 
main.cpp:17:15: error: ‘subscribers’ was not declared in this scope 
+2

Mi sono imbattuto anche in questo. Come regola generale, se coinvolge i modelli, fidati sempre di gcc su msvc (trovo che gcc sia giusto il 99,9 percento delle volte). –

+0

@JesseGood Esiste anche una duplice domanda [SO] (http://stackoverflow.com/q/11405/819272) da un altro rifugiato MSVC. Apparentemente, gcc lo ha risolto da qualche parte nella versione 3.4, rompendo alcuni vecchi codici nel processo. Ma hey, chi ha detto che i venditori hanno bisogno di compatibilità con gli errori come punto vendita? – TemplateRex

risposta

8

Questo è un bug nel MSVC invece. I nomi delle classi di base dipendenti devono essere "modificati".

Il motivo è la ricerca non qualificata dei nomi dipendenti proceeds in two phases. Durante la prima fase, la classe base non è ancora nota e il compilatore non può risolvere il nome. MSVC non implementa la ricerca di nomi in due fasi e ritarda la ricerca fino alla seconda fase.

La specializzazione completa

template<> 
struct Event<void, void> : public EventBase<Event<> > 
{ 
     void trigger() const 
     { 
       // No error here even without `this`, for some reason! 
       auto it = subscribers.cbegin(); 
     } 
}; 

non soffre di questo problema, perché sia ​​la classe e la sua base sono classi regolari, non con modelli di classe, e non v'è alcun modello di dipendenza per cominciare.

Quando il porting del codice C++ da MSVC a gcc/Clang, dipendente disambiguazione ricerca dei nomi e il template keyword disambiguation (modello ad esempio la funzione di membro chiamare utilizzando ::template, ->template o .template sintassi) sono due delle sottigliezze che si hanno a che fare con (empty base optimization è un altro). Per tutta la retorica della conformità agli standard, questo probabilmente non verrà mai risolto per ragioni di compatibilità all'indietro.

+1

Potresti spiegare ulteriormente? Perché non è un errore nell'ultimo caso? (Bel gioco di parole) – Cameron

+1

@ Cameron: l'ultimo caso non è un modello, è una specializzazione completa. Tutto su di esso è noto in fase di compilazione. –

+3

@Cameron Le domande frequenti su C++ contengono [spiegazione] (http://www.parashift.com/c++-faq-lite/nondependent-name-lookup-members.html) del perché 'this->' è richiesto in quel caso . Funziona su MSVC perché non implementa la ricerca di nomi in due fasi per i modelli. – Praetorian

Problemi correlati