10

関数テンプレートを特殊化しない理由を読み、少し実験した後、興味深いものを見つけました。ここにmain.cxxがあります:

// main.cxx
#include <iostream>

// Declarations
/*
template<class T>
void foo(T);

template<>
void foo(int*);

template<class T>
void foo(T*);
*/

// Definition and specification
template<class T>
void foo(T x)
{
    std::cout << "T version." << std::endl;
}

template<>
void foo(int *i)
{
    std::cout << "int* version." << std::endl;
}

template<class T>
void foo(T *x)
{
    std::cout << "T* version" << std::endl;
}

int main(int argc, char** argv)
{
  int *p;
  foo(p);
}

興味深いのは、宣言部分にコメントを付けたままにすると、動作は記事に記載されているとおりです。つまり、int *バージョンの定義がその定義の前にあり、その逆の場合はT*バージョンが使用されます。ただし、宣言ブロックのコメントを解除すると、定義または宣言で使用する順序に関係なく、int*バージョンのみが呼び出されます。私の質問は、この宣言がどのように決議に影響を与えるようになるのかということです。

何か案は?x86_64-redhat-linuxでg++4.2.2を使用しています

編集:AProgrammerの答えを見た後、この質問を単純化してください

4

1 に答える 1

10

ソースを3つのファイルに配布すると、問題が混乱します。前処理によって1つのコンパイル単位が作成され、動作は、配布されたファイルの数ではなく、CUのコンテンツに依存します。

この場合は驚いたと思います

#include <iostream>

template<class T> void foo(T); // A
template<> void foo(int*); // 1
template<class T> void foo(T*); // B

template<class T> void foo(T x)
{ std::cout << "T version." << std::endl; }

template<> void foo(int *i) // 2
{ std::cout << "int* version." << std::endl; }

template<class T> void foo(T *x)
{ std::cout << "T* version" << std::endl; }

int main(int argc, char** argv) {
  int *p;
  foo(p);
}

あなたが得るint* version。これは予想される動作です。(1)はの特殊化を宣言しますがtemplate <typename T> void foo(T)、(2)はその特殊化の定義ではありません。(2)スペシャライゼーションを定義および宣言し、そのスペシャライゼーションがでtemplate<class T> void foo(T*);呼び出されmain()ます。これは、宣言と定義をどのように配置しても、3つの定義の前に3つの宣言を指定した場合に発生します。定義(2)は常に宣言template<class T> void foo(T*);を参照するため、それを特殊化したものになります。

関数テンプレートの特殊化が宣言または定義されていて、それが複数の関数テンプレートの特殊化である可能性がある場合(ここで、(2)は2つのオーバーロードAとBの特殊化である可能性があり、宣言する必要があります)、それは「より専門的な」ものの専門化。「より専門化された」の正確な定義は、標準セクション17.5.5.2で確認できますが、Bが(2)のAよりもよく一致し、したがって(2)が(B)の専門化であることが非常に簡単にわかります。 。(1)は、(A)の特殊化を宣言します。これは、(1)が宣言されたときに、(B)がまだ表示されていないためです。(B)を見た後に(1)の定義を与えたい場合は、次のように書く必要があります。

template <> void foo<int*>(int*) // definition for (1)
{ std::cout << "foo<int*>(int*)\n"; }

(2)を定義するときに明示的にすることもできます。

template<> void foo<int>(int *i) // 2 alternate
{ std::cout << "int* version." << std::endl; }

(ただし、明らかに(2)を指定すると、同じCU内のこの代替バージョンでエラーが発生します)。

関数を呼び出すときにも明示的にすることができます。

foo(p); // call (2)
foo<int>(p); // call (2)
foo<int*>(p); // call (1)
于 2011-06-09T16:15:11.590 に答える