Создайте предпочтительную перегрузку, когда несколько перегрузок преодолевают SFINAE - PullRequest
3 голосов
/ 11 июля 2019
struct A { void a() { puts("a"); } };
struct B { void b() { puts("b"); } };
struct C : A, B {};

template <typename T> decltype(&T::a, (void)0) SFINAE(T t) { t.a(); }
template <typename T> decltype(&T::b, (void)0) SFINAE(T t) { t.b(); }

int foo()
{
    SFINAE(A{}); // works fine, calls a
    SFINAE(B{}); // works fine, calls b
    SFINAE(C{}); // compile error
}

Приведенный выше код завершается ошибкой при вызове SFINAE с типом, имеющим a и b, что делает оба шаблона действительными, что приводит к неоднозначному вызову. Как я могу исправить приведенный выше код, чтобы предпочесть первую перегрузку в неоднозначной ситуации? Так что SFINAE(C{}) должен позвонить a.

Ответы [ 2 ]

3 голосов
/ 11 июля 2019

Я думаю, вам нужно выразить что-то вроде

  1. имеет a и не имеет b
  2. имеет b и не имеет a
  3. имеет a и имеет b

, например

template <typename T, typename = void>
struct has_a : std::false_type {};
template <typename T>
struct has_a<T, std::void_t<decltype(&T::a)>> : std::true_type {};

template <typename T, typename = void>
struct has_b : std::false_type {};
template <typename T>
struct has_b<T, std::void_t<decltype(&T::b)>> : std::true_type {};

template <typename T> std::enable_if_t<has_a<T>::value && !has_b<T>::value> SFINAE(T t) { t.a(); }
template <typename T> std::enable_if_t<has_b<T>::value && !has_a<T>::value> SFINAE(T t) { t.b(); }
template <typename T> std::enable_if_t<has_a<T>::value && has_b<T>::value> SFINAE(T t) { t.a(); }

ЖИТЬ

Как @mch предлагает , вы можете создать свою собственную условную комбинацию, основанную на реальной ситуации.

2 голосов
/ 11 июля 2019

Вы можете устранить неоднозначность вызовов, введя преобразование:

template <typename T> decltype(&T::a, (void)0) impl(T t, int) { t.a(); }
template <typename T> decltype(&T::b, (void)0) impl(T t, unsigned) { t.b(); }

template <typename T> void SFINAE(T && t) { impl(std::forward<T>(t), 42); }

Передав 42 типа int, первая перегрузка будет выбрана компилятором в качестве лучшего соответствия.

Демо

...