【问题标题】:C++ Variadic template AND and ORC++ 可变参数模板 AND 和 OR
【发布时间】:2012-08-09 22:14:40
【问题描述】:

你能用C++11的可变参数模板完成/* ??? */ in:

template<bool...v> struct var_and { static bool constexpr value = /* ??? */; };

这样var_and&lt;v...&gt;::value 在编译时通过布尔包v 提供&amp;&amp;

你可以为struct var_or&lt;v...&gt;|| 做同样的事情吗?

您可以使用短路评估(在这两种情况下)吗?

编辑the accepted answer 的更新添加了 C++17 fold expressions 启用

template<bool... v> constexpr bool var_and = (v && ...);
template<bool... v> constexpr bool var_or  = (v || ...);

似乎,对于基于参数包的方法,只有有限类型的“短路评估”是可能的:在实例化 var_or&lt;true,foo(),bar()&gt; 时只调用一次 ||,它也同时调用 foo 和 @987654334 @。

【问题讨论】:

  • 闻起来像家庭作业。
  • @mah:我真的怀疑现在有没有教 C++11 的地方。
  • 这不是家庭作业。我正在写一个 zip 迭代器(Boost 是不够的);这个“宏”是根据布尔标志确定所有组件迭代器是否具有某个共同的属性。我确信有一种更清洁的方法。
  • 在这种情况下,作为家庭作业分配看起来是个不错的问题;)

标签: c++ c++11 variadic-templates


【解决方案1】:

您不希望 value 成为 typedef。

template<bool head, bool... tail>
struct var_and {
    static constexpr bool value = head && var_and<tail...>::value;
};

template<bool b> struct var_and<b> {
    static constexpr bool value = b;
};

显然,|| 也可以这样做。

短路评估无关紧要,因为这只处理不会有任何副作用的常量表达式。

这是另一种方法,一旦发现错误值就停止递归生成类型,模拟一种短路:

template<bool head, bool... tail>
struct var_and { static constexpr bool value = false; };

template<bool... tail> struct var_and<true,tail...> {
    static constexpr bool value = var_and<tail...>::value;
};

template<> struct var_and<true> {
    static constexpr bool value = true;
};

C++17 更新:使用折叠表达式使这变得更加简单。

template<bool...v> struct var_and {
    static constexpr bool value = (v && ...);
};

或者也使用 enobayram 建议的模板变量:

template<bool... b> constexpr bool var_and = (b && ...);

【讨论】:

  • 感谢您的回答,并使用上述问题中的typedef... 更正了我的错误。我同意短路评估无关紧要。但是,出于纯粹的学术原因,我仍然感兴趣。您能否通过以下方式获得这种行为:&lt;bool h1, bool h2, bool...tail&gt; 然后value = var_and&lt;h1 &amp;&amp; h2, tail...&gt;::value;,再加上我猜另一个基本情况?你认为编译器会利用这个吗?
  • 如果左侧的评估结果为真,则“编译时评估器”不应评估 head &amp;&amp; var_and&lt;tail...&gt;::value 的右侧.然而编译器仍然必须构造表达式,这意味着生成类型var_and&lt;tail...&gt;。由于计算是作为构造类型的一部分而不是作为评估...::value 表达式的一部分完成的,因此这种方法实际上没有短路。但是我想我知道一种方法来获得它。我将编辑我的答案。
  • 我认为您可以通过使用内联变量来进一步提升 C++17 版本:) 编译器的工作量减少,它变成了单行。
【解决方案2】:

我只需要类似的东西,但我有幸使用 C++14,所以我最终选择了以下内容,这可能比公认的答案更快(编译):

template <size_t N>
constexpr bool and_all(const bool (&bs) [N]) {
  for(bool b: bs) if(!b) return false;
  return true;
}

现在,这是 constexpr,因此它可以在编译时上下文和运行时使用。例如,我们可以在some_struct&lt;and_all({true, false, arg_pack...})&gt;这样的上下文中使用它

【讨论】:

  • 这个答案通过实施短路改进了(原始)接受的答案,并超越了运行时考虑的提出问题。尽管有这些改进,但我没有更改接受的答案,因为 (1) 我的问题明确涉及 C++11,并且 (2) 随后使用 ( C++17) fold expressions,就像 template&lt;bool... b&gt; constexpr bool var_and = (... &amp;&amp; b);,正是我最初寻求的构造。
  • 当然,接受的答案更全面,我只是想投入 2 美分。顺便说一句,要明确的是,这个答案不会在呼叫站点实现短路,这是一种语言级别的功能,仅在非常特定的情况下可用。
  • 我想我还不清楚——你能详细说明一下吗? and_all(bs) 的语义看起来与 bs[0] &amp;&amp; /* ... */ &amp;&amp; bs[N-1] 的语义相同,所以我会说前者“实现”了后者。
  • @nknight 也许我们对“短路”的理解不同。我用它来暗示这种行为,如果foo() 返回falsefoo() &amp;&amp; bar() 将永远不会评估bar()。但是如果你写and_all(foo(), bar()),两者都会在被传递给and_all之前被评估。
  • 你的理解是正确的;我现在相信所提出的解决方案都没有真正实现短路。我已经修改了我原来的问题,并添加了一条旨在澄清这一微妙之处的评论。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2022-01-23
  • 1970-01-01
  • 2016-12-01
  • 1970-01-01
  • 1970-01-01
  • 2012-05-12
相关资源
最近更新 更多