C++17 introduced structured binding declarations: auto [a, b] = some_tuple;
.
This works out of the box for things like std::tuple. It is also possible to make it work for custom types, you just have to provide (among other things) an get-function template, either as member or outside the custom class.
For the standard classes, this is done via a non-member get lying in the std-namespace: auto a = std::get<0>(some_tuple);
works, but not auto a = some_tuple.get<0>();
.
But here it gets weird for me: Since we have to explicitly specify the template parameter N for get, ADL does not work, for example, we can't just write auto a = get<0>(some_tuple);
. But then the structured binding declaration with tuples shouldn't work too, because it's just syntactic sugar for calls like either get<N>(some_tuple)
or some_tuple.get<N>()
(modulo some &
)! And indeed, when I provide only a non-member version of get for my custom class inside a namespace, it doesn't work! EDIT: Structured binding for custom classes also works fine, see the code snippet in the accepted answer for a minimal example!
So how do the implementers of the standard make structured binding work for e.g. tuples without a get as member, and how can I achieve the same behavior for my custom classes?
They cheat.
But you can emulate their cheating by adding a template get to the global namespace.
template<class T, std::enable_if_t<std::is_same<T,void>{}, bool>>
void get(int)=delete;
which should activate "parse get as a template".
You don't need to do this to get structured bindings working. As noted, the compiler just cheats:
namespace example {
struct silly {
int x;
};
template<std::size_t I>
int& get( silly& s ) { return s.x; }
}
namespace std {
template<>
struct tuple_size<::example::silly>:std::integral_constant<std::size_t, 1>{};
template<>
struct tuple_element<0, ::example::silly>{ using type=int; };
}
int main() {
example::silly s { 42 };
auto&& [x] = s;
std::cout << x;
}
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