我有一个结构
template <typename T>
struct Demo {
T x;
T y;
};
我正在尝试编写一个类似于 std::get
的通用函数对于采用编译时索引的元组 I
并返回对 I
的左值引用-结构的第一个成员,如果它是用左值调用的DemoStruct<T>
和对 I
的右值引用-结构的第一个成员,如果它是用右值调用的DemoStruct<T>
.
我目前的实现是这样的
template <size_t I, typename T>
constexpr decltype(auto) struct_get(T&& val) {
auto&& [a, b] = std::forward<T>(val);
if constexpr (I == 0) {
return std::forward<decltype(a)>(a);
} else {
return std::forward<decltype(b)>(b);
}
}
然而,这并没有达到我的预期,并且总是返回一个对 T
的右值引用相反。
Here是一个显示问题的魔杖。
返回对保留传递给函数的结构的值类别的结构成员的引用的正确方法是什么?
编辑:
正如 Kinan Al Sarmini 指出的那样,auto&& [a, b] = ...
确实推导出 a
的类型和 b
是非引用类型。 std::tuple
也是如此,例如两者
std::tuple my_tuple{std::string{"foo"}, std::string{"bar"}};
auto&& [a, b] = my_tuple;
static_assert(!std::is_reference_v<decltype(a)>);
和
std::tuple my_tuple{std::string{"foo"}, std::string{"bar"}};
auto&& [a, b] = std::move(my_tuple);
static_assert(!std::is_reference_v<decltype(a)>);
即使std::get<0>(my_tuple)
编译也很好返回引用,如
std::tuple my_tuple{3, 4};
static_assert(std::is_lvalue_reference_v<decltype(std::get<0>(my_tuple))>);
static_assert(std::is_rvalue_reference_v<decltype(std::get<0>(std::move(my_tuple)))>);
这是 GCC 和 Clang 中的语言缺陷、故意的还是错误?
最佳答案
行为是正确的。
应用于结构化绑定(bind)的decltype
返回引用类型,对于普通结构,它是引用的数据成员的声明类型(但用完整对象的 cv 限定符修饰),对于类似元组的情况是“为该元素返回的任何 tuple_element
”。这粗略地模拟了应用于普通类成员访问的 decltype
行为。
除了手动计算所需的类型,我目前想不出任何其他事情,即:
using fwd_t = std::conditional_t<std::is_lvalue_reference_v<T>,
decltype(a)&,
decltype(a)>;
return std::forward<fwd_t>(a);
关于c++ - 完美转发使用结构化绑定(bind)声明的变量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44219864/