ENABLE_IF: случай шаблонного метода шаблонной основы, наследуемой несколько раз
Вопрос
Если у меня есть базовый класс шаблона с методом шаблона:
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;
}
};
Для примера я упрощаю метод: он должен «существует», только если t == u
Если это класс:
class A : public S<int> {};
Тогда у меня есть то, что я хочу:
int i = 1;
A a;
a.f(i);
компилируется, но
double d = 2.0;
a.f(d);
Не компилируется: ошибка: нет совпадения функции для вызова
Теперь давайте наследуем от S<double>
также :
class A : public S<int>, public S<double> {};
Тогда следующий код не компилируется:
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]
Я ожидал, что нет двусмысленности: f<int>
существует только для S<int>
В ошибке компилятора мы можем заметить, что T известен, когда этот кусок кода составлен, но не U (u = u).
Любые объяснения или «обходной путь»?
Решение
Попробуй это:
a.S<int>::f(i);
... или альтернативно ввести функцию в A
, например
class A : public S<int>, public S<double>
{
public:
using S<int>::f;
using S<double>::f;
};
Другие советы
Вы правы, это существует только в S, но два раза. Однажды для каждого типа, int и удваивает. Поэтому в вашем случае вам нужно будет указать, какую именно функцию вы хотите позвонить. Решение от NIM работает так.
Другие дали хорошие обходные пути, но я хочу ответить на этот другой вопрос, который у вас был
Я ожидал, что нет двусмысленности:
f<int>
существует только дляS<int>
.
Вы сказали a.f(i)
Так что сначала нужно искать имя f
в A
. Анкет Он находит два f
с В S<int>
а также S<double>
. Анкет Во время поиска имени он еще не знает, что позже он мог выбрать только S<int>::f
как победитель, потому что S<double>::f
будет выброшен Sfinae. Четкое разделение поиска имени и разрешения перегрузки и вычета аргумента шаблона не допускает такого смешения.