2013-05-09 9 views
5

編集:これはバグではなく、ただ私がdependent name lookups in templated base classesについて知りません(MSVCは「有用に」エラーなしで解決します)。これはGCCのバグですか?


私はファンクタの実装をしばらく書いており、それを使用する単純な「イベント」ラッパーです。 MSVCの下ではうまくコンパイルされますが、GCCは基底クラスのメンバー変数であるsubscribersが宣言されていないというエラーを返します。 subscribersthis->subscribersを変更すると、問題(!)が解決されます。それは不思議な繰り返しのテンプレートパターンと、部分的なテンプレートの特殊化でのみ発生するようです。 (心曲げテンプレートの使用のために申し訳ありません...)

簡体ソース:

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

は、私がどこかに未定義の動作を呼び出すことだろうか?私の構文は何とか間違っていますか?これは本当にGCCのバグですか?おそらく既知のバグですか?どんな洞察にも感謝します!

詳細:g++ -std=c++11 main.cppを使用してコンパイルしました。私はGCCバージョン4.7.2を使用しています。正確なエラーメッセージ:

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

私もこれに遭遇しました。経験則として、テンプレートが含まれている場合は、msvcより常にgccを信頼してください(gccは99.9%の時間がかかることがわかります)。 –

+0

@JesseGoodさらに別のMSVC難民からの[SOの質問](http://stackoverflow.com/q/11405/819272)もあります。どうやら、gccは3.4リリースのどこかで修正し、プロセス内の古いコードをいくつか破壊していました。しかし、ちょっと、売り手としてバグの互換性が必要だと誰が言ったのですか? – TemplateRex

答えて

8

これは、代わりに MSVCのバグです。依存する基本クラスからの名前は、 "この曖昧さ"がなければなりません。

理由は従属名の修飾されていない参照proceeds in two phasesです。最初のフェーズでは、基本クラスは未知であり、コンパイラは名前を解決できません。 MSVCは2フェーズの名前ルックアップを実装せず、第2フェーズまでルックアップを遅延させます。

クラスとそのベースの両方が通常のクラスではなく、クラステンプレートであり、そもそも何のテンプレート依存性がないため

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

は、この問題の影響を受けない完全な専門。

(すなわち::template->templateまたは.template構文を使用してメンバ関数テンプレートを呼び出す)のgcc /クランへのMSVCからC++コード、依存名ルックアップ一義とtemplate keyword disambiguationを移植するときは、(empty base optimizationに対処する必要が微妙なの二つがあるされています別のもの)。すべての標準準拠のレトリックについては、下位互換性の理由からこれは決して修正されないでしょう。

+1

あなたはさらに説明できますか?なぜ最後のケースではエラーではないのですか? (Nice pun btw。) – Cameron

+1

@Cameron:最後のケースはテンプレートではなく、完全な専門です。コンパイル時にはすべてが分かっています。 –

+3

@Cameron C++のFAQには、この場合に 'this->'が必要な理由の[説明](http://www.parashift.com/c++-faq-lite/nondependent-name-lookup-members.html)があります。 MSVCではテンプレートの2段階名検索を実装していないため、MSVCで動作します。 – Praetorian

関連する問題