2013-05-09 20 views
5

DÜZENLEME: Bu sadece bana (msvc "yardımsever" hatasız giderir) yaklaşık dependent name lookups in templated base classes bilmeden bir hata değildir. Bu GCC'de bir hata mı?


Bir süre önce bir funktoru uygulamasını yazdım ve onu kullanan basit bir "Olay" sarıcı. MSVC altında gayet iyi derlenir, ancak GCC, beyan edilmeyen taban sınıfı subscribers'daki bir üye değişkeni hakkında bir hata verir; subscribers öğesinin this->subscribers olarak değiştirilmesi sorunu giderir (!). Sadece merakla tekrarlanan şablon kalıbıyla ve kısmi şablon uzmanlığıyla gerçekleşir. (Kafa karıştıran şablon kullanımı için üzgünüm ...)

Basitleştirilmiş kaynak:

#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; 
} 

yerde tanımlanmamış davranışı yürütmesini muyum? Benim sözdizimi bir şekilde yanlış mı? Bu gerçekten GCC'de bir hata mı? Belki de bilinen bir böcek mi? Herhangi bir içgörü takdir edilecektir!

Diğer ayrıntılar: g++ -std=c++11 main.cpp kullanılarak derlenmiştir. GCC sürüm 4.7.2 kullanıyorum. Tam hata iletisi:

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

Buna da rastladım. Genel bir kural olarak, eğer şablonları içeriyorsa, msvc üzerinden her zaman gcc'ye güvenin (gcc'nin zamanın yüzde 99.9'unu doğru buluyorum). –

+0

@JesseGood Yine bir başka MSVC mültecisinden bir çift [SO sorumlusu] (http://stackoverflow.com/q/11405/819272) bile vardır. Görünüşe göre, gcc 3.4 sürümünde bir yere sabitledi, süreçteki eski kodu kırdı. Ancak, satıcıların satış noktası olarak hataya uyumluluğa ihtiyaç duyduğunu söyleyen kim? – TemplateRex

cevap

8

Bu MSVC hata yerine olduğunu. Bağımlı temel sınıflardan gelen isimler "bubölüm" olmalıdır.

nedeni bağımlı isimlerin proceeds in two phases o niteliksiz arama olduğunu. İlk aşamada, temel sınıf henüz bilinmiyor ve derleyici adı çözemiyor. MSVC, iki fazlı isim araması uygulamaz ve ikinci aşamaya kadar aramayı geciktirir.

sınıfı ve taban hem normal sınıflar değil, sınıf şablonları olan ve başlamak için hiçbir şablon bağımlılığı olduğundan

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

, bu problemden muzdarip değil tam uzmanlaşma.

empty base optimization olduğunu (eğer uğraşmak zorunda inceliklerini ikisidir gcc/Clang, bağımlı ad arama anlam ayrımı için MSVC C++ kodu taşıma ve template keyword disambiguation (yani çağırarak üye işlevi şablon ::template, ->template veya .template sözdizimi kullanarak) Ne zaman bir diğeri). Tüm Standartlara uyum retorikleri için, bu muhtemelen geriye dönük uyumluluk nedeniyle hiçbir zaman sabitlenmeyecektir.

+1

Daha fazla açıklar mısınız? Son durumda neden bir hata değil? (Nice pun btw.) – Cameron

+1

@Cameron: Son durum bir şablon değil, tam bir uzmanlık. Bu konuda her şey derlenme zamanında bilinir. –

+3

@Cameron C++ SSS bir [açıklama] yer alır (http://www.parashift.com/c++-faq-lite/nondependent-name-lookup-members.html) This-> 'bu durumda gereklidir neden' ​​arasında . MSVC üzerinde çalışır çünkü şablonlar için iki aşamalı ad araması uygulamaz. – Praetorian