16

私の期待に反して、このプログラムは動作します:

#include <iostream>


namespace a { struct item{}; }
namespace b { struct item{}; }


template<typename T>
void func(T t) { do_func(t); }


int main()
{    
    func(a::item{});
    func(b::item{});
}


namespace a { void do_func(item) { std::cout << "a::func\n"; } }
namespace b { void do_func(item) { std::cout << "b::func\n"; } }

出力:

a::func
b::func

オンライン コンパイラによる検証:

のインスタンス化func<T>が本体で発生する場合、main私はそれを期待しa::do_funcb::do_funcまだ宣言されていません。

これはどのように機能しますか?

アップデート

@Marc Claesenによると、上記が機能する理由は次のとおりです。

テンプレートのインスタンス化は、すべてのソースを読み取った後に実行されます

ただし、このコードが機能しないのはなぜですか。

#include <iostream>

template<typename T>
void func(T t) { do_func(t); }

int main()
{
    func(1);
}

void do_func(int) { std::cout << "do_func(int)\n"; }

gcc-4.8を参照してください:

error: 'do_func' was not declared in this scope,
and no declarations were found by argument-dependent
lookup at the point of instantiation [-fpermissive]

クラン++ 3.4 :

error: call to function 'do_func' that is neither
visible in the template definition nor found by
argument-dependent lookup

そのため、機能させるには関数テンプレートと ADL の組み合わせが必要なようです。

しかし、私はなぜこれがそうであるのか理解していません..

4

1 に答える 1

14

これは、次の 2 つの興味深い理由で機能します。

  • 依存名をルックアップするために実行される2 フェーズの名前ルックアップ
  • および引数依存ルックアップ (ADL)。

これを見てください:

つまり、do_func依存名であるため、最初のフェーズ (ファイルが解析されるだけで関数テンプレートがインスタンス化されていない場合) では、コンパイラは名前を解決せず、構文のみdo_funcをチェックし、それが有効な関数呼び出しであることを確認します。 . それだけです。関数テンプレートがインスタンス化される (したがって既知になる) 2 番目のフェーズでは、名前が解決され、この時点で ADL も使用して名前を検索します。Tdo_func

ADL はユーザー定義型に対してのみ機能することに注意してください。組み込み型では機能しないため、2 番目のコード (つまりfunc(1)) は機能しません。

于 2013-05-18T11:20:09.090 に答える