abilita_if: caso del metodo modello di una base di modello ereditata più volte
Domanda
Se ho una classe base modello con un metodo modello:
template <typename T>
class S
{
public:
template <typename U>
void f(U p, typename enable_if<is_same<T, U> >::type*dummy = 0)
{
std::cout << p << std::endl;
}
};
Per l'esempio, semplifico il metodo: deve "esiste" solo se t == u
Se A è questa classe:
class A : public S<int> {};
Allora ho quello che voglio:
int i = 1;
A a;
a.f(i);
compila, ma
double d = 2.0;
a.f(d);
Non compila: Errore: nessuna funzione di corrispondenza per la chiamata a 'A :: F (Double &)' È il comportamento atteso.
Ora facciamo eredità da S<double>
anche :
class A : public S<int>, public S<double> {};
Quindi il seguente codice non si compila:
int i = 1;
A a;
a.f(i);
error: request for member ‘f’ is ambiguous error: candidates are: template<class U> void S::f(U, typename boost::enable_if<boost::is_same<T, U>, void>::type*) [with U = U, T = double] error: template<class U> void S::f(U, typename boost::enable_if<boost::is_same<T, U>, void>::type*) [with U = U, T = int]
Mi aspettavo che non ci fosse ambiguità: f<int>
esiste solo per S<int>
Nell'errore del compilatore, possiamo notare che T è noto quando questo pezzo di codice è compilato, ma non u (u = u).
Qualche spiegazione o "soluzione alternativa"?
Soluzione
Prova questo:
a.S<int>::f(i);
... o alternativamente iniettare la funzione in A
, per esempio
class A : public S<int>, public S<double>
{
public:
using S<int>::f;
using S<double>::f;
};
Altri suggerimenti
Hai ragione esiste solo in S, ma due volte. Una volta per ogni tipo, int e doppio. Quindi, nel tuo caso, dovrai specificare esattamente quale funzione vuoi chiamare. La soluzione di NIM funziona proprio così.
Others have given good workarounds, but I want to answer that other question you had
I expected there is no ambiguity :
f<int>
exists only forS<int>
.
You said a.f(i)
so it first needs to look for name f
in A
. It finds two f
s. In S<int>
and S<double>
. At name lookup time, it does not know yet that it later could have only selected S<int>::f
as a winner because S<double>::f
would be thrown away by SFINAE. The clear separation of name lookup and overload resolution and template argument deduction does not allow such intermingling.