enable_if: случай шаблонного метода базы шаблона, унаследованного несколько раз - PullRequest
2 голосов
/ 20 октября 2011

Если у меня есть базовый класс шаблона с методом шаблона:

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

Если A это класс:

class A : public S<int> {};

Тогда у меня есть то, что я хочу:

int i = 1;
A a;
a.f(i);

компилируется, но

double d = 2.0;
a.f(d);

не компилируется: ошибка:нет соответствующей функции для вызова 'A :: f (double &)'. Это ожидаемое поведение.

Теперь давайте также унаследуем A от 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).

Любое объяснение или "обходной путь"?

Ответы [ 3 ]

4 голосов
/ 20 октября 2011

Попробуйте:

a.S<int>::f(i);

... или, альтернативно, введите функцию в A, например,

class A : public S<int>, public S<double> 
{
public:
  using S<int>::f;
  using S<double>::f;
};
0 голосов
/ 23 октября 2011

Другие дали хорошие обходные пути, но я хочу ответить на тот другой вопрос, который у вас был

Я ожидал, что двусмысленности нет: f<int> существует только для S<int>.

Вы сказали a.f(i), поэтому сначала нужно найти имя f в A. Находит два f с. В S<int> и S<double>. Во время поиска имени он еще не знает, что позже он мог выбрать только S<int>::f в качестве победителя, поскольку SFINAE выбрасывает S<double>::f. Четкое разделение поиска имен и разрешения перегрузки и вывода аргументов шаблона не допускает такого смешения.

0 голосов
/ 20 октября 2011

Вы правы, он существует только в S, но два раза.Один раз для каждого типа, int и double.Так что в вашем случае вам нужно будет указать, какую именно функцию вы хотите вызвать.Решение от Nim работает так же.

...