当比较std::tuple_element和decltype(std::get)时,std::is_same返回false

7

我找不到类似的问题...

我认为有两种“简单”的方法可以在编译时获取元组第I个元素的类型(如果我错了,请纠正我):

  • using TI1 = typename std::tuple_element<I, Tuple>::type;
  • using TI2 = decltype(std::get<I>(Tuple{}));

实际上,如果我们通过 typeid(...).name() 打印每个类型,它们将返回相同的值。

然而... 如果我比较它们,std::is_same 返回 false:

在线示例

这是期望的吗?为什么?

using Tuple = std::tuple<float,double>;
constexpr size_t I = 0;
static_assert(std::is_same<typename std::tuple_element<I, Tuple>::type,
                           decltype(std::get<I>(Tuple{}))>::value, "different types" );

3
get 可能会返回一个右值引用,将 std::remove_reference_t 添加到它上面即可。 - HolyBlackCat
我很糟糕,感觉很不好。先生,您是正确的。 - bremen_matt
1个回答

7

std::get(std::tuple) 返回引用类型;这意味着使用 decltype 时,您将得到一个引用类型:

a) 如果表达式的值类别是 xvalue,则 decltype 会产生 T&&
b) 如果表达式的值类别是 lvalue,则 decltype 会产生 T&
c) 如果表达式的值类别是 prvalue,则 decltype 会产生 T

对于这种情况,std::get<I>(Tuple{}) 的返回类型是右值引用,那么 std::get<I>(Tuple{}) 是一个xvalue 表达式:

一个函数调用或重载运算符表达式,其返回类型为对象的右值引用,例如 std::move(x);

因此, decltype(std::get<I>(Tuple{})) 将是 T&&,即 float&&;这与 typename std::tuple_element<I, Tuple>::type(即 float)不同。

使用 std::remove_reference,您可以获得所需的内容。例如:

static_assert(std::is_same<typename std::tuple_element<I, Tuple>::type,
                           std::remove_reference_t<decltype(std::get<I>(Tuple{}))>>::value, "different types" );

在线

关于为什么typeid会给出相同的结果,

(重点在于)

1) 引用一个表示类型type的std::type_info对象。 如果type是引用类型,则结果引用表示被引用类型的std::type_info对象。

这意味着typeid(float&&) == typeid(float)始终是true


2
在这种情况下,我更喜欢使用std::decay,即使仅仅去除引用可能已经足够。 - eerorika

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接