结构化绑定无法编译

Mat*_*ati 3 c++

考虑以下代码片段,它引入了Test支持结构化绑定的自定义类型:

\n
struct Test {\n    int member;\n};\n\ntemplate<>\nstruct std::tuple_size<::Test>\n{\n    static constexpr size_t value = 1;\n};\n\ntemplate<>\nstruct std::tuple_element<0, ::Test>\n{\n    using type = int;\n};\n\ntemplate <size_t Index>\nconst int& get(const Test& test)\n{\n    // Omit Index for the sake of brevity\n    return test.member;\n}\n\nint main() {\n    Test test = Test{1234};\n    auto [member] = test;\n    return 0;\n}\n
Run Code Online (Sandbox Code Playgroud)\n

该代码无法编译并出现以下错误:

\n
\n

错误:将 \xe2\x80\x98std::tuple_element<0, Test>::type&\xe2\x80\x99\n{aka \xe2\x80\x98int&\xe2\x80\x99} 类型的引用绑定到 \xe2\ x80\x98const int\xe2\x80\x99 丢弃限定符

\n
\n

根据我的理解,结构化绑定应扩展为(测试转换为 xvalue 并传递给get函数):

\n
\n

在这些初始化表达式中,如果实体 e 的类型是左值引用(仅当引用限定符为 & 或为 && 并且初始化表达式是左值时才会发生这种情况)和 xvalue,则 e 是左值。否则(这有效地执行了一种完美转发),i 是一个 std::size_t 纯右值,并且始终被解释为模板参数列表。

\n
\n

https://en.cppreference.com/w/cpp/language/structured_binding

\n
Test test = Test{1234};\nTest hidden = Test(test);\nconst int& member = get<0UL>(static_cast<Test &&>(hidden));\n
Run Code Online (Sandbox Code Playgroud)\n

编译得很好。然而,看起来 const 限定符被遗漏了,而member\ 的类型int&由于明显的原因无法编译并产生类似的错误消息。

\n

Hol*_*Cat 5

而不是const int &member,你会得到int &member

参考参数

[类型是] 引用std::tuple_element<i, E>::type, ... 如果其相应的初始值设定项是左值,则为左值引用,否则为右值引用

E在哪里std::remove_reference_t<decltype((hidden))>,又名Test。而“相应的初始值设定项”就是您的get()返回值。

std::tuple_element自动const从其模板参数传播到结果类型,但它没有帮助,因为它E不是const首先的。


这归结为get没有正确书写。const对于、非const&的所有组合,您需要 4 个重载&&

这些可以压缩为:

template <size_t Index, typename T>
requires std::is_same_v<std::remove_cvref_t<T>, Test>
auto &&get(T &&test)
{
    return std::forward<T>(test).member;
}
Run Code Online (Sandbox Code Playgroud)

或者,如果您希望在使用元组协议时使类型为只读,请强制tuple_element始终为const

template<>
struct std::tuple_element<0, ::Test>
{
    using type = const int;
};
Run Code Online (Sandbox Code Playgroud)