为什么"std::forward_as_tuple(1)"不是常量表达式?

Why isn't `std::forward_as_tuple(1)` a constant expression?

本文关键字:常量 表达式 tuple forward std as 为什么      更新时间:2023-10-16
#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<int&&>,根据clang的说法,它创建了一个对临时的引用,使其不是constexpr。替代方案不适用于我需要的 - std::make_tuple()不能用于完美的转发,std::tie也不能存储文字值。编辑:为什么std::forward_as_tuple()以这种方式工作而不提供替代方案?

我在这里做错了什么根本性的事情,还是有什么我不明白的地方?

std::forward_as_tuple这样

工作,因为它被指定为返回一个引用元组以实现完美转发。如果你想要一个函数在使用 1xstd::move(y) 调用时返回 std::tuple<int,X&,Y>,那么编写一个:

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

演示