はい、可能ですが、コードを少し変更する必要があります。
まず、技術的には、2番目の関数f()
はテンプレート関数の特殊化ではなく、オーバーロードです。A
オーバーロードを解決するとき、型が完全に一致しないため、型がないすべての引数に対してテンプレートバージョンが選択されます。引数の型T
と等しいと推定されるためf(b)
、たとえば、型推定後にコンパイラは次のようになります。次の2つのオーバーロードから選択します。
void f(B&){printf("template\n");}
void f(A&){printf("specialization\n");}
もちろん、最初のものがより良い一致です。
ここで、のサブクラスである引数を使用して関数が呼び出されたときに2番目のバージョンを選択する場合は、A
SFINAE手法を使用して、タイプ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()
てくださいvoid
。enable_if