4

次のコードを検討してください。

#include <stdio.h>

namespace Foo {
  template <typename T>
  void foo(T *, int) { puts("T"); }

  template <typename T>
  struct foo_fun {
    static void fun() { foo((T *)0, 0); };
  };
}

namespace Foo {
  void foo(int *, int) { puts("int"); }
}

using namespace Foo;

int main() {
  foo_fun<int> fun;
  fun.fun();
}

期待される出力は何ですか?「T」またはint?

1つのコンパイラ(AppleのXcode3.1.2のgcc4.0.1)は「int」を出力し、他の2つのコンパイラ(gcc 4.1.2および4.1.3)は「T」を出力します。

foo(int *、int)宣言/定義をfoo(T *、int)バージョンの前に移動すると、すべて「int」が出力されます。この場合のオーバーロード/特殊化の順序は、現在の標準で定義されていますか?

4

2 に答える 2

9

2つ目は、の定義では表示されないため、テンプレート定義のコンテキストでは検出されvoid foo(...ないオーバーロード(特殊化ではない)です。は依存型であるfoo_fun::funため、式の解決はテンプレートのインスタンス化時間まで遅延され、インスタンス化のコンテキストも考慮されます。ただし、標準の14.6.4.2では、関数名が非修飾IDであり、テンプレートIDではない場合、非ADLルックアップでは、テンプレートの定義時に表示される関数のみが考慮されるとされています。名前空間からの関数引数がないため、引数に依存するルックアップは発生しません。したがって、テンプレートバージョンはT*foofoo((T*)0, 0)Foofooが呼び出され、非テンプレートのオーバーロードではありません。

この答えを訂正してくれたlitbに感謝します。

以下のように特殊化した場合、テンプレートのインスタンス化時に特殊化が選択されるため、関数テンプレートが最初にインスタンス化された時点で関連する特殊化が表示されている限り、特殊化を呼び出すことができますint

namespace Foo {
    template<>
    void foo<int>(int *, int) { puts("int"); }
}

現在の規格の第14章ですが、あまり読みやすくありません:)

編集:標準の最も関連性のある部分を選択する必要がある場合は、おそらく14.6 [temp.res]パラ9になります。(少し省略)名前がテンプレートパラメータに依存しない場合、その名前の宣言は次のようになります。テンプレート定義で名前が表示されるポイントのスコープ内。名前はその時点で見つかった宣言にバインドされ、このバインドはインスタンス化の時点で表示される宣言の影響を受けません。

編集、編集:ただし、14.6.4.2[temp.dep.candidate]も考慮する必要があります。すべての相互依存性のために、標準を参照しようとすることは非常に困難で危険です。この答えはその好例です。

于 2008-12-31T20:16:37.800 に答える
0

原則として、コンパイラの 2 つのバージョンのうち、後者の方がより標準的である可能性が高くなります。

于 2008-12-31T20:30:16.743 に答える