Create a preferred overload when multiple overloads make it past SFINAE

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
}

The above code fails when calling SFINAE with a type that has a and b, thus making both templates valid resulting in an ambiguous call. How can I fix the above code to prefer the first overload in an ambiguous situation? So SFINAE(C{}) should call a.

Upvotes: 3

Views: 192

Answers (2)

O&#39;Neil
O&#39;Neil

Reputation: 3849

You can disambiguate the calls by introducing a conversion:

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); }

Passing 42 of type int, the first overload will be selected by the compiler as better match.

Demo

Upvotes: 3

songyuanyao
songyuanyao

Reputation: 172934

I think you need to express something like

  1. has a and has not b
  2. has b and has not a
  3. has a and has b

e.g.

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(); }

LIVE

As @mch suggested, you can make your own conditional combination based on the actual situation.

Upvotes: 3

Related Questions