boost.Hana 中的 when<> 特性如何工作?
How the when<> trait in boost.Hana works?
我对 std::enable_if
有一些经验。 IIRC,它是关于格式正确的表达式是否导致 true
return 返回用户类型 T(如果给定)或通过嵌套类型别名无效。
template<bool,typename = void>
struct enable_if;
template<typename T>
struct enable_if<true,T>{
using type = T;
};
template <typename T, typename = void>
struct base_template{
enum { value= false};
};
template <typename T>
struct base_template<T, typename enable_if<std::is_integral<T>::value>::type> {
enum { value= true};// something useful...
};
struct some{};
static_assert(base_template<some>::value,"F*"); //error: static assertion failed: F
static_assert(base_template<int>::value,"F*");
但是在 boost.Hana 中我看到了这个特性 when<> 并且它的实现就像
template <bool condition>
struct when;
template <typename T, typename = when<true>>
struct base_template{
enum { value= false};
};
template <typename T>
struct base_template<T, when<std::is_integral<T>::value>> {
enum { value= true};// something useful...
};
struct some{};
static_assert(base_template<int>::value,"F*");
static_assert(base_template<some>::value,"F*");<source>:28:15: error: static assertion failed: F*
SFINAE 在这里如何运作?尽管 std::is_integral<some>::value
会导致 false,但这并不意味着(确实如此?)when<false>
是 ill-formed
并且应该将实例化分派给主 class模板。我在这里遗漏了什么吗?
大意是一样的。您可以以基本相同的方式使用 enable_if_t
或 decltype
。现在,您可能已经习惯了看到像这样的 SFINAE 偏特化:
template<class T, class U = void>
struct Foo {};
template<class T>
struct Foo<T, decltype(T::bar())> {};
... Foo<X> ...
这里,Foo<X>
首先被编译器扩展为Foo<X, void>
(因为你在"call site"处没有提供U
,所以默认U = void
被填入)。然后,编译器查找 class 模板 Foo
的 best-matching 特化。如果 decltype(X::bar())
实际上是 void
,那么 Foo<T, decltype(T::bar())> [with T=X]
将是 Foo<X, void>
的完美匹配。否则,将使用通用 Foo<T, U> [with T=X, U=void]
。
现在以 Hana when
为例。
template<bool> struct when {};
template<class T, class U = when<true>>
struct Foo {};
template<class T>
struct Foo<T, when<T::baz>> {};
... Foo<X> ...
这里,Foo<X>
首先被编译器扩展为Foo<X, when<true>>
(因为你在"call site"处没有提供U
,所以默认U = when<true>
被填入)。然后,编译器查找 class 模板 Foo
的 best-matching 特化。如果 when<X::baz>
实际上是 when<true>
,那么 Foo<T, when<T::baz>> [with T=X]
将是 Foo<X, when<true>>
的完美匹配。否则,将使用通用 Foo<T, U> [with T=X, U=when<true>]
。
您可以用任意复杂的布尔表达式替换我示例中的简单表达式 T::baz
,只要它是 constexpr-evaluable。在您的原始示例中,表达式为 std::is_integral<T>::value
.
我的 CppCon 2017 session "A Soupçon of SFINAE" 介绍了一些类似的例子。
我对 std::enable_if
有一些经验。 IIRC,它是关于格式正确的表达式是否导致 true
return 返回用户类型 T(如果给定)或通过嵌套类型别名无效。
template<bool,typename = void>
struct enable_if;
template<typename T>
struct enable_if<true,T>{
using type = T;
};
template <typename T, typename = void>
struct base_template{
enum { value= false};
};
template <typename T>
struct base_template<T, typename enable_if<std::is_integral<T>::value>::type> {
enum { value= true};// something useful...
};
struct some{};
static_assert(base_template<some>::value,"F*"); //error: static assertion failed: F
static_assert(base_template<int>::value,"F*");
但是在 boost.Hana 中我看到了这个特性 when<> 并且它的实现就像
template <bool condition>
struct when;
template <typename T, typename = when<true>>
struct base_template{
enum { value= false};
};
template <typename T>
struct base_template<T, when<std::is_integral<T>::value>> {
enum { value= true};// something useful...
};
struct some{};
static_assert(base_template<int>::value,"F*");
static_assert(base_template<some>::value,"F*");<source>:28:15: error: static assertion failed: F*
SFINAE 在这里如何运作?尽管 std::is_integral<some>::value
会导致 false,但这并不意味着(确实如此?)when<false>
是 ill-formed
并且应该将实例化分派给主 class模板。我在这里遗漏了什么吗?
大意是一样的。您可以以基本相同的方式使用 enable_if_t
或 decltype
。现在,您可能已经习惯了看到像这样的 SFINAE 偏特化:
template<class T, class U = void>
struct Foo {};
template<class T>
struct Foo<T, decltype(T::bar())> {};
... Foo<X> ...
这里,Foo<X>
首先被编译器扩展为Foo<X, void>
(因为你在"call site"处没有提供U
,所以默认U = void
被填入)。然后,编译器查找 class 模板 Foo
的 best-matching 特化。如果 decltype(X::bar())
实际上是 void
,那么 Foo<T, decltype(T::bar())> [with T=X]
将是 Foo<X, void>
的完美匹配。否则,将使用通用 Foo<T, U> [with T=X, U=void]
。
现在以 Hana when
为例。
template<bool> struct when {};
template<class T, class U = when<true>>
struct Foo {};
template<class T>
struct Foo<T, when<T::baz>> {};
... Foo<X> ...
这里,Foo<X>
首先被编译器扩展为Foo<X, when<true>>
(因为你在"call site"处没有提供U
,所以默认U = when<true>
被填入)。然后,编译器查找 class 模板 Foo
的 best-matching 特化。如果 when<X::baz>
实际上是 when<true>
,那么 Foo<T, when<T::baz>> [with T=X]
将是 Foo<X, when<true>>
的完美匹配。否则,将使用通用 Foo<T, U> [with T=X, U=when<true>]
。
您可以用任意复杂的布尔表达式替换我示例中的简单表达式 T::baz
,只要它是 constexpr-evaluable。在您的原始示例中,表达式为 std::is_integral<T>::value
.
我的 CppCon 2017 session "A Soupçon of SFINAE" 介绍了一些类似的例子。