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