get
のオーバーロードが見つからないため、次のコードは期待どおりに失敗します。 std::get
を使用すると、問題が解決します。
#include <array>
int main()
{
std::array<int, 2> ar{2,3};
auto r = get<0>(ar);//fails, get was not declared in this scope
}
ただし、get
のテンプレートバージョンを導入すると、関数呼び出しに一致していなくても、コンパイラは何らかの形でstd::get
バージョンを使用します。
#include <array>
template <typename T>
void get(){};
int main()
{
std::array<int, 2> ar{2,3};
auto r = get<0>(ar);//returns 2
}
これを説明する標準の部分は見つかりません。これは私がテストした3つのコンパイラすべてのバグですか(おそらくそうではないでしょうか)、または何か不足していますか?
この動作はでテストされました
編集:私はADLを知っています。しかし、ADLが2番目のコードを機能させる場合、なぜ最初の部分では機能しないのですか?
呼び出しポイントでテンプレート関数宣言を導入しない限り、明示的なテンプレート引数が関係する場合、ADLは使用されません。型のないテンプレート引数_0
_を使用する非修飾形式のget
を使用しているため、テンプレート関数宣言を導入するか、修飾されたバージョンのget
をstd::get<0>(ar)
。
標準の_[temp.arg.explicit]/8
_ ::(emphasis mine)
[注:単純な関数名の場合、関数名が呼び出しのスコープ内で表示されない場合でも、引数依存ルックアップ(6.4.2)が適用されます。これは、呼び出しがまだ関数呼び出しの構文形式を持っているためです(6.4.1)。 ただし、明示的なテンプレート引数を持つ関数テンプレートが使用される場合、呼び出しの時点でその名前の関数テンプレートが表示されない限り、呼び出しには正しい構文形式がありません。そのような名前が表示されない場合、呼び出しは構文的に整形式ではなく、引数依存のルックアップは適用されません。そのような名前が表示される場合、引数に依存するルックアップが適用され、他の名前空間に追加の関数テンプレートが見つかる場合があります。
編集:
@Yakk-Adam Nevraumontがコメントで指摘したように、テンプレート関数宣言が存在しない場合、式get<0>(ar)
は_(get<0)>(ar)
_として解析されます。つまり、関数呼び出し。
これは、 P0846R0 の結果としてC++ 20で変更されたことに注意してください。非修飾名とそれに続く<
トークンは、通常の非修飾ルックアップが1つ以上の関数を検出するか、何も検出しない場合、テンプレートと<
はそれに応じて解析されます。