Tak, jest to możliwe, ale trzeba trochę zmienić kod.
Przede wszystkim, aby mieć charakter techniczny, druga funkcja f()
jest nie specjalizacja funkcji szablonu, ale przeciążenia . Podczas rozwiązywania przeciążenia wersja szablonu jest wybierana dla wszystkich argumentów, których typ nie jest A
, ponieważ jest idealnie dopasowany: T
jest wyprowadzony jako równy typowi argumentu, więc podczas wywoływania f(b)
, na przykład, po odliczeniu typu, kompilator będzie musiał wybrać między dwoma następującymi przeciążeniami:
void f(B&){printf("template\n");}
void f(A&){printf("specialization\n");}
Oczywiście pierwszy jest lepszy.
Teraz, jeśli chcesz wybrać drugą wersję, gdy funkcja jest wywoływana z argumentem będącym podklasą A
, musisz użyć pewnej techniki SFINAE, aby uniemożliwić prawidłowe tworzenie szablonu funkcji, gdy typ T
jest wywnioskować, że jest podklasą A
.
Możesz użyć std::enable_if
w połączeniu z cechami typu std::is_base_of
, aby to osiągnąć.
// 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; }
Oto jak można go używać w pełnym programie:
#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"
}
EDIT:
Jeśli pracujesz z kompilatora, który nie jest w pełni zgodny z C++ 11 (i dlatego nie obsługuje domyślnych szablonów argumentów na szablonach funkcji), możesz zmienić definicję przeciążenia szablonu na f()
w następujący sposób:
template<typename T>
typename enable_if<!is_base_of<A, T>::value, void>::type
f(T&) { cout << ("template\n"); }
Zachowanie programu będzie identyczne. Zwróć uwagę, że jeśli typem powrotu jest f()
jest void
, możesz pominąć drugi argument w szablonie klasy enable_if
.
Co dokładnie masz na myśli? Pytanie jest całkowicie niejednoznaczne. –
@Desolator Oznacza on, że chce, aby wszystko, co pochodzi od A, jak również z instancji A, wykorzystywało przesłonięcie do odniesienia A, a nie ogólne rozwinięcie szablonu. Jego wezwania do używania 'foo()' z instancjami 'B' i' C' używają generycznego, a nie przesłonięcia. – WhozCraig
@WhozCraig Dzięki! Właśnie tego chcę. Klasy pochodne A mają funkcję, którą muszę wywołać. Inne typy nie mają tej funkcji i zamiast tego muszę użyć cech. – Felics