【问题标题】:How the when<> trait in boost.Hana works?boost.Hana 中的 when<> 特征如何工作?
【发布时间】:2018-06-09 14:52:29
【问题描述】:

我对@9​​87654321@ 有一些经验。 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 中我看到了这个特性 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&lt;some&gt;::value 会导致错误,但这并不意味着(它会?)when&lt;false&gt;ill-formed 并且应该将实例化分配给主类模板。我在这里有什么遗漏吗?

【问题讨论】:

  • @ildjarn 当然它们并不相同,因为enable_if_t 是一个类型别名,而when 是一个类模板,不像enable_if_t 我看不到when 拉任何嵌套类型关闭。

标签: c++ c++14 boost-hana


【解决方案1】:

这是相同的一般想法。您可以以基本相同的方式使用enable_if_tdecltype。现在,您可能已经习惯于看到这样的 SFINAE 部分专业化:

template<class T, class U = void>
struct Foo {};

template<class T>
struct Foo<T, decltype(T::bar())> {};

... Foo<X> ...

这里,Foo&lt;X&gt;首先被编译器扩展为Foo&lt;X, void&gt;(因为你没有在“调用点”处提供U,所以改为填写默认的U = void)。然后,编译器查找类模板Foo 的最佳匹配特化。如果decltype(X::bar()) 实际上是void,那么Foo&lt;T, decltype(T::bar())&gt; [with T=X] 将是Foo&lt;X, void&gt; 的完美匹配。否则,将使用通用的Foo&lt;T, U&gt; [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&lt;X&gt;首先被编译器扩展为Foo&lt;X, when&lt;true&gt;&gt;(因为你没有在“调用点”处提供U,所以改为填写默认的U = when&lt;true&gt;)。然后,编译器寻找类模板Foo 的最佳匹配特化。如果when&lt;X::baz&gt; 实际上是when&lt;true&gt;,那么Foo&lt;T, when&lt;T::baz&gt;&gt; [with T=X] 将是Foo&lt;X, when&lt;true&gt;&gt; 的完美匹配。否则,将使用通用的Foo&lt;T, U&gt; [with T=X, U=when&lt;true&gt;]

您可以将我示例中的简单表达式 T::baz 替换为任意复杂的布尔表达式,只要它是 constexpr 可评估的。在您的原始示例中,表达式为 std::is_integral&lt;T&gt;::value

我的 CppCon 2017 会议"A Soupçon of SFINAE" 介绍了一些类似的示例。

【讨论】:

  • 那么专业化的第二种类型与默认参数匹配还是使用主模板的特殊规则?我知道发生了什么,但我不明白“为什么”。
  • 主模板是“最不专业”的版本;部分专业化是“更专业化”。在其他条件相同的情况下,编译器将选择尽可能专业化(最不通用)的版本,在这种情况下,这意味着选择部分专业化 Foo&lt;T, void&gt; [with T=X] 而不是专业化程度较低的 Foo&lt;T, U&gt; [with T=X, U=void]。如果我们写了一个完整的特化template&lt;&gt; struct Foo&lt;X, void&gt; {},那么编译器会选择Foo&lt;X, void&gt;而不是不太特化的Foo&lt;T, void&gt; [with T=X]。这就是模板专业化起作用的原因。
猜你喜欢
  • 2022-10-07
  • 2015-12-04
  • 1970-01-01
  • 2018-04-01
  • 2018-09-25
  • 2019-08-13
  • 2011-11-06
  • 2013-01-04
  • 2011-11-30
相关资源
最近更新 更多