2016-11-12 2 views
5

Компиляции этого кода:Неоднозначный вызов не избежать SFINAE

#include <iostream> 


template <int N> 
struct TestClass { 
    template <int N2, typename std::enable_if<N2 == N, int>::type = 0> 
    void doAction() { std::cout << "TestClass::doAction<" << N << ">();\n"; } 
}; 

struct HostClass : public TestClass<1>, public TestClass<2> { 
}; 


int main(int argc, const char * argv[]) { 
    HostClass hostClass; 

    hostClass.doAction<1>(); 
    hostClass.doAction<2>(); 

    return 0; 
} 

приводит к неоднозначной ошибке вызова, потому что doAction одновременно в TestClass<1> и TestClass<2> родительских классах.

main.cpp: 33: 15: УЧАСТНИК DoAction "находится в нескольких базовых классах различных типов

Но std::enable_if не отключит эту неоднозначность?

EDIT:

Я думаю, что реальная причина этой неоднозначности является тем же, чем в этом вопросе:

Why do multiple-inherited functions with same name but different signatures not get treated as overloaded functions?

Неоднозначность может быть решена, как показано в ответ с using ключевое слово:

#include <iostream> 


template <int N> 
struct TestClass { 
    template <int N2, typename std::enable_if<N2 == N, int>::type = 0> 
    void doAction() { std::cout << "TestClass::doAction<" << N << ">();\n"; } 
}; 

struct HostClass : public TestClass<1>, public TestClass<2> { 
    using TestClass<1>::doAction; 
    using TestClass<2>::doAction; 
}; 

int main(int argc, const char * argv[]) { 
    HostClass hostClass; 

    hostClass.doAction<1>(); // OK, compile 
    hostClass.doAction<2>(); // OK, compile 
    //hostClass.doAction<3>(); // OK, doesn't compile : "candidate template ignored: disabled by 'enable_if' [with N2 = 3]" 

    return 0; 
} 

Я не знаю, было ли это wh в ответе @skypjack, но я все равно допустил его альтернативный метод.

ответ

5

Это могло бы (позвольте мне сказать) удалить одну из двух функций после замены.
В любом случае, прежде всего, компилятор должен решить, какую функцию вы собираетесь использовать при вызове doAction<1>, , затем, он может продолжить замену и в конечном итоге отбросить выбранную функцию из-за sfinae.
В момент вызова оба из них являются действительными кандидатами, и вызов действительно двусмыслен.

Обратите внимание, что, как это было предложено @ Peregring-лк в комментариях, TestClass<1>::doAction и TestClass<2>::doAction две различные функции, помещенные в разных пространствах имен, они не являются перегруженные той же функции.
Это на самом деле общий источник недоразумений.


Вы можете легко решить эту проблему, как это следующим образом:

#include <iostream> 

template <int N> 
struct TestClass { 
    void doAction() { std::cout << "TestClass::doAction<" << N << ">();\n"; } 
}; 

struct HostClass : public TestClass<1>, public TestClass<2> { 
    template<int N> 
    void doAction() { return TestClass<N>::doAction(); } 
}; 


int main(int argc, const char * argv[]) { 
    HostClass hostClass; 

    hostClass.doAction<1>(); 
    hostClass.doAction<2>(); 

    return 0; 
} 
+0

Для большей наглядности добавить, что 'TestClass <1> :: doAction' и' TestClass <2> :: doAction' две разные функции, и а не перегрузки одной и той же функции, общий источник недоразумений. –

+0

@ Peregring-lk Done. Благодарю. – skypjack

Смежные вопросы