【发布时间】:2016-01-27 09:24:19
【问题描述】:
当有人提到某个特定函数、结构或 ... SFINAE 友好时,我无法清楚地理解它的含义。
谁能解释一下?
【问题讨论】:
当有人提到某个特定函数、结构或 ... 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>>
{
};
【讨论】:
int = 0 与 ... 不明确吗?
call_f<WithoutF>上做SFINAE?
int 比...更专业
如果一个实体可以在 SFINAE 的上下文中使用而不会在替换失败时产生硬错误,那么它就被称为 SFINAE 友好的。我假设您已经知道 SFINAE 是什么,因为这本身就是另一个问题。
在 C++ 标准化的上下文中,SFINAE-friendly 一词迄今已应用于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 产生替换失败,因此从可行集合中排除了重载。
【讨论】: