14

今日は順調です。ここにn00bの質問番号7があります:

テンプレート関数をオーバーロードしようとしたときの明示的な特殊化と通常の関数の違いは何ですか?

明示的な特殊化を使用するための適切な状況は何ですか?私はそれを完全には理解していません:

#include <iostream>

template <typename s> void test(s var1);
template <> void test<int>(int var1);

int main(){
    test(1);
    test(1.1);
    test("hello!!");
    return 0;
}

template <typename s> void test(s var1){
    std::cout << var1 << std::endl;
}

template <> void test<int>(int var1){
    std::cout << "int " << var1 << std::endl;
}

反対に:

#include <iostream>

template <typename s> void test(s var1);
void test(int var1);

int main(){
    test(1);
    test(1.1);
    test("hello!!");
    return 0;
}

template <typename s> void test(s var1){
    std::cout << var1 << std::endl;
}

void test(int var1){
    std::cout << "int " << var1 << std::endl;
}
4

5 に答える 5

6

コンパイラが関数呼び出しに一致する署名タイプを探すときに、最初に一致する非テンプレート関数を選択するという事実を除いて、明示的に特殊化されたテンプレート関数と非テンプレート通常関数の間に実際の違いはありません。必要な署名の一致を満たす可能性のある使用可能なテンプレート関数をインスタンス化する前に、必要な署名。

ただし、テンプレート関数ではないヘッダーファイル内で関数を宣言および定義する場合は、関数をとして宣言する必要がありますinline。これは、テンプレート関数は、実際にインスタンス化されるまで、コードモジュールにリンクされている実際の関数ではないためです。リンカは、コードモジュールをコンパイルした後、そのインスタンス化を破棄します。リンカがこれを行わなかった場合、.cppファイルにヘッダーファイルが含まれるたびに、リンカは関数の定義が重複していると文句を言います。テンプレート以外の関数でキーワードを使用するinlineと、コンパイラレベルでも同様の効果があります。つまり、関数が.cppファイルで使用されると、コンパイラはその関数呼び出しを、からの関数コードの本体に置き換えます。inlineヘッダーファイル内の関数であり、関連するスタックアクティブレコードのセットアップとクリーンアップを伴う関数呼び出しのオーバーヘッドを回避します。したがって、リンカは関数の重複定義について文句を言うことはありません。

于 2011-05-13T03:28:03.933 に答える
3

主な違いは次のとおりです。明示的な特殊化はオーバーロードにまったく関与しません。

template<typename T> void f(T const&);
template<> void f<char const*>(char const * const&);

で呼び出すとf("hello")、明示的な専門分野は考慮されません。すべてのテンプレートのみを取得し、それらのテンプレート引数を推測します。上記Tはに推論されるchar[6]ため、専門分野は選択されません。

代わりに関数テンプレートをオーバーロードすると、まったく異なる特性が得られます。

template<typename T> void f(T const&);
void f(char const * const&);

これを呼び出す(char const(&)[6])と、生成された特殊化の(char const * const&)パラメーターとパラメーターの両方が引数と等しくよく一致するため、2番目の関数が選択されますが、2番目の関数は非テンプレート関数であるため、最終的には優先されます。

于 2011-05-13T10:09:05.727 に答える
3

私は専門家ではありませんが、さまざまなリターンタイプを定義する場合は、テンプレート(および特殊化)を使用する経験があります。関数の戻り型をオーバーロードすることはできません。

于 2012-07-21T00:12:48.657 に答える
1

コンパイラが関数呼び出しに遭遇すると、最初に非テンプレート関数定義を探し、次に明示的に特殊化されたテンプレートを探し、最後に署名が関数呼び出しと一致するテンプレート定義を探します。したがって、たとえば、明示的に定義されたテンプレートとテンプレートがある場合、コンパイラーは明示的に定義されたテンプレートに対応します。したがって、テンプレートが処理する方法とは異なる方法で特定のデータ型を処理する場合は、明示的に特殊化されたテンプレートを使用する必要があります。

明示的な特殊化のもう1つの用途は、引数をとらない関数を「オーバーロード」する場合です。明示的な特殊化を使用して、さまざまなデータ型を処理するために関数にさまざまな定義を与えることができます。

于 2017-12-09T20:10:31.517 に答える
0

IMHO、明示的function templateなテンプレート引数を使用してその関数を呼び出す場合は、の明示的な特殊化を使用する必要があります。例えば

test<int>(myClass); // no argument for 'int' -> declare test() as template specialization

それ以外の場合は、常に通常の特殊化を使用する必要があります。例えば

test(10, myClass); // argument 10 is 'int' -> test() should be normal specialized

技術的には、関数の通常のテンプレート特殊化と明示的なテンプレート特殊化の間に違いはありません。通常の特殊バージョンは、template機能から完全に独立しています。

于 2011-05-13T03:31:08.057 に答える