9

我正在尝试支持类的类似元组的结构化绑定访问。为简单起见,我将在本文的其余部分使用以下类:

struct Test
{
    int v = 42;
};

(我知道这个类支持开箱即用的结构化绑定,但我们假设它不支持。)

启用对 的成员的类似元组的访问Test,我们必须专门化std::tuple_sizestd::tuple_element

namespace std
{

template<>
struct tuple_size<Test>
{
    static const std::size_t value = 1;
};

template<std::size_t I>
struct tuple_element<I, Test>
{
    using type = int;
};

}

我们需要的最后一部分是或 的命名空间中的Test::get<i>一个函数。让我们实现后者:get<i>(Test)Test

template<std::size_t I>
int get(Test t)
{
    return t.v;
}

这行得通。但是,我想返回对Test的成员的引用std::get(std::tuple),例如 。因此,我实现get如下:

template<std::size_t I>
int& get(Test& t)
{
    return t.v;
}

template<std::size_t I>
const int& get(const Test& t)
{
    return t.v;
}

但是,对于此版本,以下代码

auto test = Test{};
auto [v] = test;

产生错误(GCC 7.1):

将 'std::tuple_element<0, Test>::type& {aka int&}' 类型的引用绑定到 'const int' 丢弃限定符

因此,似乎为get<i>(const Test&)结构化绑定选择了重载。由于此重载返回 a const int&,并且v像对 的非const引用一样int,因此代码无法编译。

然而,据此,auto [v] = test;应该大致相当于

auto e = test;
std::tuple_element<0, Test>::type& v = get<0>(e)

确实有效,因为它使用了get<i>(Test&)重载。

关于为什么我的实现get不适用于结构化绑定的任何想法?

4

1 回答 1

7

问题是这auto [v]是一个非引用声明,所以test被复制并且副本作为 xvaluetest传递给。get

所以你需要添加一个右值限定的get:

template<std::size_t I>
int&& get(Test&& t)
{
    return std::move(t.v);
}
于 2017-08-15T18:29:43.603 回答