当有人说某事对 SFINAE 友好时,这是什么意思?

What does it mean when one says something is SFINAE-friendly?

当有人提到某个特定函数、结构或... SFINAE 友好.

时,我无法清楚地理解它的含义

有人能解释一下吗?

当它允许没有硬错误的替换失败时(如static_assert)。

例如

template <typename T>
void call_f(const T& t)
{
    t.f();
}

该函数是为所有 T 声明的,即使没有 f 的函数也是如此,因此您不能在 call_f<WithoutF> 上执行 SFINAE,因为该方法确实存在。 (非编译代码的Demo)。

有以下变化:

template <typename T>
auto call_f(const T& t) ->decltype(t.f(), void())
{
    t.f();
}

该方法 用于有效 T。 所以你可以使用 SFINAE 作为

template<typename T>
auto call_f_if_available_impl(const T& t, int) -> decltype(call_f(t))
{
    call_f(t);
}

template<typename T>
auto call_f_if_available_impl(const T& t, ...)
{
    // Do nothing;
}

 template<typename T>
 auto call_f_if_available(const T& t)
 {
    call_f_if_available_impl(t, 0);
 }

注意int = 0...是为了重载。 Demo

--

另一种情况是模板添加特殊参数申请SFINAE专业化:

template <typename T, typename Enabler = void> struct S;

然后

// Specialization only available for T which respect the traits.
template <typename T>
struct S<T, std::enable_if_t<my_type_trait<T>::value>>
{
};

如果一个实体可以在 SFINAE 的上下文中使用而不会在替换失败时产生硬错误,则该实体被称为 SFINAE-friendly。我假设您已经知道 SFINAE 是什么,因为这本身就是另一个问题。

在 C++ 标准化的上下文中,术语 SFINAE-friendly 目前已应用于 std::result_ofstd::common_type。举个例子:

template <typename T>
void foo(T x, typename std::common_type<T, int>::type y) {}

void foo(std::string x, std::string y) {}

int main()
{
    foo(std::string("hello"), std::string("world"));
}

如果没有 SFINAE-friendly common_type,这将无法编译,因为 std::common_type<std::string, int>::type 会在模板参数替换期间产生硬错误。随着 SFINAE-friendly common_type (N3843) 的引入,这个例子变成了 well-formed,因为 std::common_type<std::string, int>::type 产生了替换失败,因此过载被排除在可行集之外。

这里有一个与 result_of 类似的例子:

template <typename T>
auto bar(T f) -> typename std::result_of<T()>::type { return f(); }

void bar(int n) {}

int main()
{
    bar(42);
}

如果没有 SFINAE-friendly result_of,这将无法编译,因为 std::result_of<int()>::type 会在模板参数替换期间产生硬错误。随着 SFINAE-friendly result_of (N3462) 的引入,这个例子变成了 well-formed,因为 std::result_of<int()>::type 产生了替换失败,因此过载被排除在可行集之外。