v.foo
テンプレート型 ( ) の変数から非テンプレート属性 ( ) にアクセスするT& v
場合、同じ名前のテンプレート関数 ( ) がある場合、C++ はだまされてメンバー テンプレートであると認識される可能性があることがわかりましたtemplate class <T> void foo()
。これは C++ 仕様からどのように説明できますか? 次の簡単なプログラムを考えてみましょう:
#include <cassert>
/** Determine whether the 'foo' attribute of an object is negative. */
template <class T>
bool foo_negative(T& v)
{
return v.foo < 0;
}
struct X
{
int foo;
};
int main()
{
X x;
x.foo = 5;
assert(!foo_negative(x));
return 0;
}
foo_negative
任意のタイプのオブジェクトを受け取り、その foo 属性が負かどうかを判断するテンプレート関数があります。main
関数は [T = X] でインスタンス化されfoo_negative
ます。このプログラムは、出力なしでコンパイルおよび実行されます。
次に、この関数をプログラムの先頭に追加します。
template <class T>
void foo()
{
}
G++ 4.6.3 でコンパイルすると、次のコンパイラ エラーが発生します。
funcs.cpp: In function ‘bool foo_negative(T&)’:
funcs.cpp:13:14: error: parse error in template argument list
funcs.cpp: In function ‘bool foo_negative(T&) [with T = X]’:
funcs.cpp:25:5: instantiated from here
funcs.cpp:13:14: error: ‘foo’ is not a member template function
(13return v.foo < 0
行目と 25 行目はassert(!foo_negative(x))
です。)
Clang も同様のエラーを生成します。
ワット?呼び出されることのない無関係な関数を追加して、有効なプログラムに構文エラーをどのように導入したのでしょうか? を解析するときfoo_negative
、コンパイラは の型を認識していません。v
また、重要なことに、 がv.foo
メンバー テンプレートであるか通常のメンバーであるかも認識していません。どうやら、解析時 (テンプレートがインスタンス化される前) に、それをメンバー テンプレートとして扱うか通常のメンバーとして扱うかを決定する必要があります。
v.foo
がメンバー テンプレートであると判断した場合、はテンプレート引数< 0
として渡さ0
れていると見なされ、 が欠落>
しているため、構文エラーになります。次に、foo_negative
[T = X] でインスタンス化するとX::foo
、メンバー テンプレートではないため、別のエラーが発生します。
しかし、なぜv.foo
メンバー テンプレートであると考えるのでしょうか。このあいまいさはまさにtemplate
キーワードの目的です: と書いた場合v.template foo
、C++ にメンバー テンプレートを期待するように明示的に指示することになりますが、template
キーワードを使用しませんでした! メンバー テンプレートを参照していないので、通常のメンバーであると想定する必要があります。メンバーと同じ名前の関数があるという事実は、何の効果もないはずです。なぜですか?GCC と clang は一貫しているため、コンパイラのバグではありません。