c++ - 完美转发使用结构化绑定(bind)声明的变量

标签 c++ language-lawyer c++17 perfect-forwarding structured-bindings

我有一个结构

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/

相关文章:

c++ - 在调用 std::rethrow_exception 可移植后,是否销毁指向异常的最后一个 std::exception_ptr?

c++ - 在 C++ 中,是否定义了通过 char* 删除基本类型(例如 uint32_t)的行为?

c++ - 为什么标准没有提供 erase-remove-idiom 的便利助手?

c++ - 转换为 std::optional<T> 时 Clang 和 GCC 中的不同结果

c++ - 如何通过可变参数模板将多个构造函数参数转发到数组初始值设定项列表?

c++ - 编写/设计一个简单的对象管理器(游戏上下文)

c++ - 为什么我的 switch/case 在使用枚举时默认?

c++ - 为什么带有指针子对象的文字类类型的constexpr表达式不能是非类型模板参数

c++ - std::stringstream 相当于 u32string?

c++ - C++ 应用程序中的持久数据/设置