web-dev-qa-db-ja.com

名前空間を調べるオーバーロード解決

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つのコンパイラすべてのバグですか(おそらくそうではないでしょうか)、または何か不足していますか?

この動作はでテストされました

  • MSVC 15.9.2
  • Clang 8.0.0
  • GCC 9.0.0(まだ実験的なバージョン)

編集:私はADLを知っています。しかし、ADLが2番目のコードを機能させる場合、なぜ最初の部分では機能しないのですか?

34
LcdDrm

呼び出しポイントでテンプレート関数宣言を導入しない限り、明示的なテンプレート引数が関係する場合、ADLは使用されません。型のないテンプレート引数_0_を使用する非修飾形式のgetを使用しているため、テンプレート関数宣言を導入するか、修飾されたバージョンのgetstd::get<0>(ar)

標準の_[temp.arg.explicit]/8_ ::(emphasis mine)

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

編集:

@Yakk-Adam Nevraumontがコメントで指摘したように、テンプレート関数宣言が存在しない場合、式get<0>(ar)は_(get<0)>(ar)_として解析されます。つまり、関数呼び出し。

20
Jans

これは、 P0846R0 の結果としてC++ 20で変更されたことに注意してください。非修飾名とそれに続く<トークンは、通常の非修飾ルックアップが1つ以上の関数を検出するか、何も検出しない場合、テンプレートと<はそれに応じて解析されます。

4
T.C.