I'm trying to support tuple-like structured binding access for a class. For simplicity, I'll use the following class in the rest of this post:
struct Test
{
int v = 42;
};
(I'm aware that this class supports structured bindings out of the box but let's assume it does not.)
To enable tuple-like access to the member of Test
, we must specialize std::tuple_size
and std::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;
};
}
And the last part we need is either Test::get<i>
or a function get<i>(Test)
in Test
's namespace. Let's implement the latter:
template<std::size_t I>
int get(Test t)
{
return t.v;
}
This works. However, I would like to return a reference to Test
's member, just like std::get(std::tuple)
, for example. Therefore, I implement get
as follows:
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;
}
With this version, however, the following code
auto test = Test{};
auto [v] = test;
produces an error (GCC 7.1):
binding reference of type ‘std::tuple_element<0, Test>::type& {aka int&}’ to ‘const int’ discards qualifiers
So it seems as if the get<i>(const Test&)
overload is selected for the structured binding. Since this overload returns a const int&
, and v
acts like a non-const
reference to int
, the code fails to compile.
According to this, however, the line auto [v] = test;
should be roughly equivalent to
auto e = test;
std::tuple_element<0, Test>::type& v = get<0>(e)
Which does work since it uses the get<i>(Test&)
overload.
Any ideas on why my implementation of get
does not work for structured bindings?
The problem is that auto [v]
is a non-reference declaration, so test
is copied and the copy of test
is passed to get
as an xvalue.
So you need to add an rvalue qualified get:
template<std::size_t I>
int&& get(Test&& t)
{
return std::move(t.v);
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With