15

私はこの単純なコードを持っています:

class A{};
class B : public A{};
class C : public B{};

class Test
{
    public:
        template<typename T>
        void f(T&){printf("template\n");}
        void f(A&){printf("specialization\n");}
};

int main()
{
    A a;
    B b;
    C c;

    Test test;
    test.f(a);
    test.f(b);
    test.f(c);
}

それを実行すると(VS2010)、次の出力があります:

specialization
template
template

A-derived特殊化を使用するためにクラスで呼び出しを行うことは可能ですか?

4

1 に答える 1

20

はい、可能ですが、コードを少し変更する必要があります。

まず、技術的には、2番目の関数f()はテンプレート関数の特殊化ではなくオーバーロードです。Aオーバーロードを解決するとき、型が完全に一致しないため、型がないすべての引数に対してテンプレートバージョンが選択されます。引数の型Tと等しいと推定されるためf(b)、たとえば、型推定後にコンパイラは次のようになります。次の2つのオーバーロードから選択します。

void f(B&){printf("template\n");}
void f(A&){printf("specialization\n");}

もちろん、最初のものがより良い一致です。

ここで、のサブクラスである引数を使用して関数が呼び出されたときに2番目のバージョンを選択する場合は、ASFINAE手法を使用して、タイプTがのサブクラスであると推定されたときに関数テンプレートが正しくインスタンス化されないようにする必要があります。 A

これを実現するために、タイプ特性とstd::enable_if組み合わせて使用​​できます。std::is_base_of

// This will get instantiated only for those T which are not derived from A
template<typename T,
    typename enable_if<
        !is_base_of<A, T>::value
        >::type* = nullptr
    >
void f(T&) { cout << "template" << endl; }

完全なプログラムでどのように使用するかを次に示します。

#include <type_traits>
#include <iostream>

using namespace std;

class A{};
class B : public A{};
class C : public B{};
class D {};

class Test
{
    public:

        template<typename T,
            typename enable_if<!is_base_of<A, T>::value>::type* = nullptr
            >
        void f(T&) { cout << ("template\n"); }

        void f(A&){ cout << ("non-template\n");}

};

int main()
{
    A a;
    B b;
    C c;
    D d;
    float f;

    Test test;
    test.f(a); // Will print "non-template"
    test.f(b); // Will print "non-template"
    test.f(c); // Will print "non-template"
    test.f(d); // Will print "template"
    test.f(f); // Will print "template"
}

編集:

C ++ 11に完全に準拠していない(したがって、関数テンプレートのデフォルトのテンプレート引数をサポートしていない)コンパイラを使用している場合は、テンプレートのオーバーロードの定義をf()次のように変更することをお勧めします。

template<typename T>
typename enable_if<!is_base_of<A, T>::value, void>::type 
f(T&) { cout << ("template\n"); }

プログラムの動作は同じになります。の戻り型がである場合、クラステンプレートの2番目の引数を省略できることに注意しf()てくださいvoidenable_if

于 2013-02-10T11:44:37.307 に答える