为什么声明函数的顺序会改变 SFINAE 选择的重载?

Why does order of declaring function changes overload chosen by SFINAE?

这个问题与有关。

在此示例中,SFINAE 使用变量模板 has_literal_x 专业化而不是基本模板:

struct A { };
A operator"" _x(char const*) { return {}; }

template<typename T, typename S, typename = void>
constexpr bool has_literal_x = false;

template<typename T, typename S>
constexpr bool has_literal_x<T, S, 
    std::enable_if_t<
        std::is_same<
            decltype(operator""_x(std::declval<S>())), T
            >::value
        >
    > = true;


int main()
{  
    std::cout << has_literal_x<A, char const*> << std::endl; // 1
}

此处使用基本模板:

template<typename T, typename S, typename = void>
constexpr bool has_literal_x = false;

template<typename T, typename S>
constexpr bool has_literal_x<T, S, 
    std::enable_if_t<
        std::is_same<
            decltype(operator""_x(std::declval<S>())), T
            >::value
        >
    > = true;

struct A { };
A operator"" _x(char const*) { return {}; }

int main()
{  
    std::cout << has_literal_x<A, char const*> << std::endl; // 0
}

在 GCC (first, second) and Clang (first, second) 中,定义模板和用户文字的顺序发生了变化,SFINAE 选择了哪些重载。为什么?

这是沼泽标准两阶段查找问题的变体。对于依赖函数名称,

  • 非限定查找仅考虑模板定义上下文
  • 参数相关查找同时考虑模板定义上下文和模板实例化上下文。

对于第二种情况,模板定义上下文中的非限定查找没有找到任何内容,并且 const char * 没有 ADL。