23

重複の可能性:
ADL が関数テンプレートを見つけられないのはなぜですか?

呼び出しgetは、引数依存のルックアップを呼び出していないようです:

auto t = std::make_tuple(false, false, true);
bool a = get<0>(t);        // error
bool b = std::get<0>(t);   // okay

g++ 4.6.0 は次のように述べています。

error: 'get' was not declared in this scope

Visual Studio 2010 は次のように述べています。

error C2065: 'get': undeclared identifier

なんで?

4

2 に答える 2

22

これは、テンプレート引数として指定することにより、関数テンプレートを明示的にインスタンス化しようとするためです。テンプレートの場合、呼び出し時にその名前の関数テンプレートが表示されていれば、ADL は機能します。この可視関数テンプレートは、ADLのトリガーを支援するだけであり (実際には使用されない場合があります)、他の名前空間で最も一致するものを見つけることができます。get0

ADLをトリガー(または有効化)する関数テンプレートには、定義が必要ないことに注意してください。

namespace M
{
    struct S{};

    template<int N, typename T>
    void get(T) {}     
}

namespace N
{
   template<typename T>
   void get(T); //no need to provide definition
                // as far as enabling ADL is concerned!
} 

void f(M::S s)
{
   get<0>(s); //doesn't work - name `get` is not visible here 
}

void g(M::S s)
{
   using N::get; //enable ADL
   get<0>(s); //calls M::get
}

ではg()、名前はN::getを呼び出すときに ADL をトリガーしますget<0>(s)

デモ : http://ideone.com/83WOW


C++ (2003) セクション §14.8.1/6 の読み取り、

[注: 単純な関数名の場合、呼び出しのスコープ内で関数名が表示されない場合でも、引数依存のルックアップ (3.4.2) が適用されます。これは、呼び出しが関数呼び出し (3.4.1) の構文形式のままであるためです。ただし、明示的なテンプレート引数を持つ関数テンプレートが使用されている場合、呼び出しの時点でその名前の関数テンプレートが表示されていない限り、呼び出しは正しい構文形式になりません。そのような名前が表示されない場合、呼び出しは構文的に整形式ではなく、引数依存のルックアップは適用されません。そのような名前が表示されている場合、引数に依存するルックアップが適用され、追加の関数テンプレートが他の名前空間で見つかる場合があります。

[例:

namespace A {
     struct B { };
     template<int X> void f(B);
}
namespace C {
     template<class T> void f(T t);
}
void g(A::B b) {
     f<3>(b);    //ill-formed: not a function call
     A::f<3>(b); //well-formed
     C::f<3>(b); //ill-formed; argument dependent lookup
                 // applies only to unqualified names

    using C::f;
     f<3>(b); //well-formed because C::f is visible; then
              // A::f is found by argument dependent lookup
}

—例の終わり] —終わりのメモ]

于 2011-09-11T08:16:12.710 に答える
13

ADL はなどのtemplate-idに直接適用されないget<0>ため、コンパイラは実際にはそのパスを開始しません。C++11 §14.8.1/8 (C++03、14.8.1/6):

[ 注: 単純な関数名の場合、呼び出しのスコープ内で関数名が表示されない場合でも、引数依存のルックアップ (3.4.2) が適用されます。これは、呼び出しが関数呼び出し (3.4.1) の構文形式のままであるためです。ただし、明示的なテンプレート引数を持つ関数テンプレートが使用されている場合、呼び出しの時点でその名前の関数テンプレートが表示されていない限り、呼び出しは正しい構文形式になりません。そのような名前が表示されない場合、呼び出しは構文的に整形式ではなく、引数依存のルックアップは適用されません。そのような名前が表示されている場合、引数に依存するルックアップが適用され、追加の関数テンプレートが他の名前空間で見つかる場合があります。

短い例を挙げます。したがって、回避策は非常に簡単です。

#include <tuple>

template< typename > // BEGIN STUPID BUT HARMLESS HACK
void get( struct not_used_for_anything ); // END STUPIDITY

auto t = std::make_tuple(false, false, true);
bool a = get<0>(t);        // Now the compiler knows to use ADL!
bool b = std::get<0>(t);   // okay

http://ideone.com/fb8Ai

not_used_for_anything上記の は単なる安全機構であることに注意してください。決して完成しない不完全な型を意図しています。省略しても機能しますが、必要な署名と衝突する可能性があるため安全ではありません。

template< typename >
void get() = delete;

http://ideone.com/WwF2y

注: 標準からの上記の引用は規範的ではありません。つまり、委員会の意見では、説明なしでこれを理解できるということです。これは、残りの言語と文法、特に 3.4 という事実によって暗示されているためです。 .2 テンプレート ID の検索については何も述べていません。そうだね!

于 2011-09-11T09:15:35.280 に答える