2015-01-15 14 views
9

以下の構造のコードがあります(実際はもっと複雑ですが、特に "Base"は3ライナーですが、その要旨)キャプチャ:私は本当に理解していない打ち鳴らすと++私は、エラーメッセージが表示されます、'using'ステートメントがg ++でコンパイルされ、clangでコンパイルに失敗する

g++ -c test.cpp -std=c++11 

しかし経由

template <class T> 
class A {}; 

template <class T> 
class B { 
public: 
    B(){}; 
}; 

template <class T> 
class C : public B<A<T>> { 
public: 
    using Base = B<A<T>>; 
    using Base::B; 
}; 

static const C<int> c{}; 

コードをg ++で罰金コンパイルを

clang++ -c test.cpp -std=c++11 

test.cpp:14:14: error: dependent using declaration resolved to type without 'typename' using Base::B;

私のコードに問題がありますか、これはclangのバグですか?

注:using B<A<T>>::B;を書くとき、両方のコンパイラでうまくコンパイルされますが、これは私の問題の本当の解決策ではありません。

編集:打ち鳴らすのバージョンは、gccのバージョン3.5.0でセクション12.1から4.9.2

+4

継承コンストラクタを使用する場合、 'using'は型ではなくコンストラクタに名前を付けます。したがって、' typename'は間違っています。とにかく、 'Base :: Base'を使うのはうまくいくはずです - それをコンストラクタに解決する特別なルックアップがあります。 http://coliru.stacked-crooked.com/a/5e01aeb4d26b312e –

+0

ご説明いただきありがとうございます。 'Using Base :: Base'は、私のプロダクションコードの素晴らしい解決策です。しかしながら、「Base :: Bを使用する」が有効であるかどうかは疑問である。私にとって、 'typename'の間違った言及は、clangに何か問題があることを示唆しています。私はC++の専門家ではありません。 –

+0

はい、これが打ち鳴らすのバグのように見えます。そこ 'B を使用しない理由は、Bは::>ません;'と 'ベース:: Bを使用して、'別々に扱われるべきです。 –

答えて

3

この場合には、(リチャード・スミスhttps://llvm.org/bugs/show_bug.cgi?id=23107#c1に応じて)C++委員会で議論されているとの事は今より明確に得ている:

using Base::B 

は有効なコードであることを意図しないです。

using Base::Base 

しかし、打ち鳴らすことによって生成されるエラーメッセージが誤解を招くあり、うまくいけば、このバグレポートの一部として解決される:

以下の方法は、クラスエイリアスBaseを導入する際に、コンストラクタの継承を表現するための正しい方法であります(https://llvm.org/bugs/show_bug.cgi?id=22242)。

+0

3年後、バグはまだ解明されていないとエラーメッセージがまだ誤解を招くです:( – Danra

3

です:

Constructors do not have names

だから、有資格のルックアップのための通常の規則が適用されません。代わりに、コンストラクタのルックアップ(セクション3.4.3.1)のための特別なルールに依存する必要があります。

In a lookup in which function names are not ignored and the nested-name-specifier nominates a class C :

— if the name specified after the nested-name-specifier, when looked up in C , is the injected-class-name of C , or

in a using-declaration (7.3.3) that is a member-declaration, if the name specified after the nested-name-specifier is the same as the identifier or the simple-template-id’s template-name in the last component of the nested-name-specifier,

the name is instead considered to name the constructor of class C .

だから、確かに

using Base::Base; 

代わりの

using Base::B; 

あなたの元のバージョンを書くことができます最初の箇条書きで動作するはずですが、テンプレートが含まれていると、クラス名の注入は複雑になります。簡単なバージョンのBase::Baseといっしょに読みやすくなっています。そのことをすぐに知る人は、あなたがコンストラクタの名前を知っていることを知っています。

関連する問題