我对std::enable_if
有一些经验。 IIRC,它是关于一个结构良好的表达式导致true
返回用户类型T(如果给定)或通过嵌套类型别名返回void。
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中,当&lt;&gt;时,我看到了这个特征它的实现就像
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
会导致错误,但when<false>
是ill-formed
并不意味着(确实如此?)并且应该将实例化分派给主类模板。我在这里错过了什么吗?
答案 0 :(得分:2)
这是一般的想法。您可以以基本相同的方式使用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>
(因为您未在“呼叫网站”处提供U
,因此默认U = void
为填写而来)。然后,编译器查找类模板Foo
的最佳匹配特化。如果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>>
(因为您未在“呼叫网站”处提供U
,因此默认U = when<true>
为填写而来)。然后,编译器查找类模板Foo
的最佳匹配特化。如果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会话"A Soupçon of SFINAE"介绍了一些类似的例子。