当多个重载超过SFINAE时创建首选重载

时间:2019-07-11 11:03:32

标签: c++ templates c++14

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
}

当使用类型为ab的类型调用SFINAE时,以上代码将失败,从而使两个模板均有效,从而导致模棱两可的调用。在不明确的情况下,我该如何修复上面的代码来优先选择第一个重载?因此,SFINAE(C{})应该呼叫a

2 个答案:

答案 0 :(得分:3)

我认为您需要表达

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

https://paste.ubuntu.com/p/k23rbRkgFt/

作为@mch LIVE,您可以根据实际情况进行自己的条件组合。

答案 1 :(得分:2)

您可以通过引入转化来消除通话歧义:

create or replace FUNCTION splitSizeBRD(
          curveValue IN VARCHAR2)
        RETURN sizeBRD PIPELINED
      AS
        l_string LONG := curveValue || chr(38);
        l_comma_index PLS_INTEGER;
        l_index PLS_INTEGER := 1;
      BEGIN
       LOOP
         l_comma_index := INSTR(l_string, chr(38), l_index);
         EXIT
       WHEN l_comma_index = 0;
         PIPE ROW ( TRIM(SUBSTR(l_string,  l_index, l_comma_index - l_index)));
         l_index := l_comma_index + 1;
       END LOOP;
       RETURN;
     END splitSizeBRD;

传递类型为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); } 的{​​{1}}时,编译器将选择第一个重载作为更好的匹配。

Demo