質問

C ++仕様のどの部分が、関連する名前空間のセットで関数テンプレートを見つけることから引数依存の検索を制限しますか?言い換えれば、なぜ最後の呼びかけは main 以下はコンパイルに失敗しますか?

namespace ns {
    struct foo {};
    template<int i> void frob(foo const&) {}
    void non_template(foo const&) {}
}

int main() {
    ns::foo f;
    non_template(f); // This is fine.
    frob<0>(f); // This is not.
}
役に立ちましたか?

解決

この部分はそれを説明しています:

C ++標準03 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
}

他のヒント

わずかに受け入れられた答えを改良したいと思います。 OPの質問では明らかではありませんが、標準の重要な部分(Kornelが引用)はこれ(強調鉱山)です。

ただし、関数テンプレートがある場合 明示的なテンプレート引数 使用されている場合、通話には正しい構文フォームがありません

したがって、禁止されているのは、ADLに依存し、明示的なテンプレート引数を使用することです。残念ながら、非タイプのテンプレート引数を使用するには、明示的な引数を使用する必要があります(デフォルト値がない限り)。

以下はこれを示すサンプルコードです。

住む

#include <string>
#include <utility>

namespace C {
  struct B { };
  template<class T> void f(T t){}
}

void g(C::B b) {
  f(b);           // OK
  //f<C::B>(b);   // ill-formed: not a function call, but only 
                  //  because explicit template argument were used

  std::string s;
  move(s);                      // OK
  //move<std::string&>(s);      // Error, again because 
                                //  explicit template argument were used
  std::move<std::string&>(s);   // Ok
}

int main()
{
 C::B b;
 g(b);
}

C ++ 20以降、ADLは明示的な関数テンプレートでも正常に動作します。これが提案です:P0846R0:表示されていないADLおよび関数テンプレート:

ユーザーにテンプレートキーワードを使用するように要求する代わりに、通常のルックアップが結果を生成しないか、1つ以上の関数を見つけ、AA "<"が続く名前のいずれかの名前が次のように扱われるように、ルックアップルールの改訂が提案されました。関数テンプレート名が見つかった場合、ADLが実行されます。

現在、GCC 9のみがこの機能を実装しているため、例をコンパイルできます。

live demo.

編集:いいえ、これは正しくありません。見る @Kornelの答え.


確かではありませんが、Stroustrupの「C ++プログラミング言語」に相談したことがあります。 そうかもしれない 原因になります。

以来 frob それを専門とすることができるテンプレートです i=0 あなたがそれを呼んだ後の時点で。これは、実装にどれが選択する2つの可能な方法が残されていることを意味します。 frob 表示されているように呼び出すには、インスタンス化の時点でそれを選択できます また 翻訳ユニットの処理の終了時。

だから、私は問題はあなたができることだと思います

namespace ns {
    struct foo {};
    template<int i> void frob(foo const&) {}
}

int main() {
    ns::foo f;
    frob<0>(f);
    return 0;
}

namespace ns {
    template<> void frob< 0 >(foo const&) { /* Do something different*/ }
}
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top