当一个人说SFINAE友好时,这是什么意思?

时间:2016-01-27 09:24:20

标签: c++ sfinae

当人们提到特定的功能,结构或......是 SFINAE友好时,我无法清楚地理解其含义。

请有人解释一下吗?

2 个答案:

答案 0 :(得分:22)

当它允许替换失败而没有硬错误时(如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>>
{
};

答案 1 :(得分:4)

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

在C ++标准化的背景下,到目前为止,SFINAE友好一词已应用于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友好common_type,这将无法编译,因为std::common_type<std::string, int>::type会在模板参数替换期间产生硬错误。随着SFINAE友好common_typeN3843)的引入,此示例变得格式正确,因为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友好result_of,这将无法编译,因为std::result_of<int()>::type会在模板参数替换期间产生硬错误。随着SFINAE友好result_ofN3462)的引入,此示例变得格式正确,因为std::result_of<int()>::type会导致替换失败,从而从可行集中排除重载。