当有人说某事对 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_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-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
产生了替换失败,因此过载被排除在可行集之外。
当有人提到某个特定函数、结构或... 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_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-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
产生了替换失败,因此过载被排除在可行集之外。