【问题标题】:Why isn't `std::forward_as_tuple(1)` a constant expression?为什么 `std::forward_as_tuple(1)` 不是常量表达式?
【发布时间】:2015-01-05 21:41:10
【问题描述】:
#include <tuple>

int main() {
  static_assert(std::is_same<std::tuple<int&&>,
                             decltype(std::forward_as_tuple(1))>::value, "");
  constexpr int x = 5;
  constexpr auto t1 = std::forward_as_tuple(1);  // (1)
  constexpr auto t2 = std::forward_as_tuple(x);  // (2)
  constexpr std::tuple<int&&> t3(1);             // (3)
  constexpr std::tuple<int> t4(1); // OK!
}

在上面的代码中,static_assert 通过了,但是第 1 行到第 3 行无法使用 gcc 4.9(由 ubuntu 提供)和 clang 进行编译。他们抱怨变量不是由constexprs 初始化的,x 不是constexpr(即使它是由文字初始化的),这是创建对临时的引用,或者他们对forward_as_tuple() 的实现是不是(尽管 C++14 标准确实保证了这一点)。

我正在编写一些大量使用std::tupleconstexpr 的代码。我可以绕过std::forward_as_tuple() 不被定义为constexpr,但我不明白为什么forward_as_tuple(0) 会返回tuple&lt;int&amp;&amp;&gt;,根据clang 创建一个临时引用,使其不是constexpr。替代方案不能满足我的需要——std::make_tuple() 不能用于完美转发,std::tie 不能存储文字值。 编辑:为什么std::forward_as_tuple() 以这种方式工作而没有提供替代方案?

我在这里做的是根本错误的事情还是我不明白的事情?

【问题讨论】:

  • ...forward_as_tuple 返回std::tuple&lt;Types&amp;&amp;...&gt;。您希望forward_as_tuple(0) 返回什么类型?什么Types...int 更正确?即,您已经证明会发生什么:您期望发生什么(对于每一行)。它用于完美转发:它返回引用或右值引用的元组。可以写一个存储右值的,它不是很长,如果你想要的话。
  • 你不能拥有constexpr int&amp;&amp; var = ..
  • 如果我通过了std::forward_as_tuple(1,x,std::move(y)),我会期待std::tuple&lt;int,X&amp;,Y&gt;。我不明白为什么std::forward_as_tuple 认为tuple&lt;int&amp;&amp;, X&amp; &amp;&amp;, Y&amp;&amp;&gt; 在某种程度上更有用或更正确,并且不提供forward_as_tuple 在文字上有效的版本。换句话说,forward_as_tuple 似乎并没有正确转发。
  • 因为能够命名类型并不意味着创建该类型的实例是合法的。

标签: c++ c++14 stdtuple


【解决方案1】:

std::forward_as_tuple 之所以如此工作,是因为它被指定返回一个引用元组以进行完美转发。如果你想要一个在使用1xstd::move(y) 调用时返回std::tuple&lt;int,X&amp;,Y&gt; 的函数,那么写一个:

template <typename...Ts>
constexpr std::tuple<Ts...> foo(Ts&&...ts) {
  return std::tuple<Ts...>{std::forward<Ts>(ts)...};
}

DEMO

【讨论】:

  • 不确定是不是我的措辞,但这并不能回答我的问题。因此,如果t = std::forward_as_tuple(0, x) 将返回std::tuple&lt;int&amp;&amp;, X&amp; &amp;&amp;&gt;,那么std::get&lt;0&gt;(t) 将返回int&amp;&amp;std::get&lt;1&gt;(t) 将返回X&amp; &amp;&amp;,如果传递给另一个函数,它们将被完美转发。但是t = foo(0, x)std::get&lt;0&gt;(std::move(t))std::get&lt;1&gt;(std::move(t)) 不会得到同样的效果吗?这不也很完美吗?
猜你喜欢
  • 1970-01-01
  • 2019-06-22
  • 1970-01-01
  • 2019-11-13
  • 2022-10-08
  • 2011-11-15
  • 2019-06-22
  • 1970-01-01
  • 2014-08-26
相关资源
最近更新 更多