Sì, è possibile, ma è necessario modificare il codice un po '.
Prima di tutto, essere tecnico, la seconda funzione è f()
non una specializzazione del modello di funzione, ma un sovraccarico. Quando si risolve il sovraccarico, la versione del modello viene scelta per tutti gli argomenti il cui tipo non è A
, perché è una corrispondenza perfetta: T
viene dedotto per essere uguale al tipo dell'argomento, quindi quando si chiama f(b)
, ad esempio, dopo la deduzione di tipo il il compilatore dovrà scegliere tra i seguenti due sovraccarichi:
void f(B&){printf("template\n");}
void f(A&){printf("specialization\n");}
Naturalmente, il primo è una corrispondenza migliore.
Ora se si desidera selezionare la seconda versione quando si richiama la funzione con un argomento che è una sottoclasse di A
, è necessario utilizzare una tecnica SFINAE per impedire che il modello di funzione venga istanziato correttamente quando il tipo T
è dedotta per essere una sottoclasse di A
.
È possibile utilizzare std::enable_if
in combinazione con i tratti del tipo std::is_base_of
per ottenere ciò.
// 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; }
Ecco come si usa in un programma completo:
#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:
Se si sta lavorando con un compilatore che non è completamente compatibile con C++ 11 (e quindi non supporta gli argomenti del modello predefinito sui modelli di funzione), potrebbe essere necessario modificare la definizione del sovraccarico del modello di f()
come segue:
template<typename T>
typename enable_if<!is_base_of<A, T>::value, void>::type
f(T&) { cout << ("template\n"); }
Il comportamento del programma sarà identico. Notare che se il tipo restituito di f()
è void
, è possibile omettere il secondo argomento del modello di classe enable_if
.
Cosa intendi esattamente? La domanda è totalmente ambigua –
@Desolator Significa che vuole che tutto ciò che deriva da A e le istanze A stesse usino l'override per un riferimento A piuttosto che per l'espansione del modello generico. Le sue chiamate a usare 'foo()' con istanze 'B' e' C' stanno usando il generico, non l'override. – WhozCraig
@WhozCraig Grazie! Questo è esattamente quello che voglio. Le classi derivate da A hanno una funzione che devo chiamare. Gli altri tipi non hanno questa funzione e ho bisogno di usare invece le caratteristiche. – Felics