Jar*_*d42 23
当它允许替换失败而没有硬错误(as static_assert
).
例如
template <typename T>
void call_f(const T& t)
{
t.f();
}
Run Code Online (Sandbox Code Playgroud)
该函数是为所有人声明的T
,即使是那些没有的函数f
,因此您无法进行SFINAE,call_f<WithoutF>
因为该方法确实存在.(非编译代码的演示).
随着以下变化:
template <typename T>
auto call_f(const T& t) ->decltype(t.f(), void())
{
t.f();
}
Run Code Online (Sandbox Code Playgroud)
该方法仅适用于有效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);
}
Run Code Online (Sandbox Code Playgroud)
注意int = 0
并且...
是订购过载.
演示
-
另一种情况是模板添加特殊参数以应用SFINAE进行专业化:
template <typename T, typename Enabler = void> struct S;
Run Code Online (Sandbox Code Playgroud)
然后
// Specialization only available for T which respect the traits.
template <typename T>
struct S<T, std::enable_if_t<my_type_trait<T>::value>>
{
};
Run Code Online (Sandbox Code Playgroud)
如果一个实体可以在 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"));
}
Run Code Online (Sandbox Code Playgroud)
如果没有 SFINAE-Friendly common_type
,这将无法编译,因为std::common_type<std::string, int>::type
会在模板参数替换期间产生硬错误。common_type
随着 SFINAE 友好型( 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);
}
Run Code Online (Sandbox Code Playgroud)
如果没有 SFINAE-Friendly result_of
,这将无法编译,因为std::result_of<int()>::type
会在模板参数替换期间产生硬错误。result_of
随着 SFINAE 友好型( N3462 )的引入,这个示例变得格式良好,因为std::result_of<int()>::type
会产生替换失败,从而将过载从可行集中排除。