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 は一貫しているため、コンパイラのバグではありません。