当人们提到特定的功能,结构或......是 SFINAE友好时,我无法清楚地理解其含义。
请有人解释一下吗?
答案 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_of
和std::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_type
(N3843)的引入,此示例变得格式正确,因为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_of
(N3462)的引入,此示例变得格式正确,因为std::result_of<int()>::type
会导致替换失败,从而从可行集中排除重载。