I was wondering if it was possible to use fact that in
struct Foo
{
int x;
};
int main()
{
Foo foo;
auto [a0] = foo;
auto [a1, b1] = foo;
auto [a2, b2, c2] = foo;
// auto [a, b, c, ...] = foo;
}
only the first structured-binding is valid, in order to create metafunction that takes any pod type and returns a tuple consisting of all the member types of the passed pod, e.g. for Foo it would return
std::tuple<int>
I tried something like this, but that didn't work out:
#include <tuple>
#include <type_traits>
#include <utility>
using namespace std;
template<typename T, typename U = void>
struct to_tuple;
template<typename T>
struct to_tuple<T, void_t<decltype([](T x) {
auto [a] = x;
return make_tuple(a);
}(declval<T>()))>>
{
using type = decltype([](T x) {
auto [a] = x;
return make_tuple(a);
}(declval<T>()));
};
template<typename T>
struct to_tuple<T, void_t<decltype([](T x) {
auto [a, b] = x;
return make_tuple(a, b);
}(declval<T>()))>>
{
using type = decltype([](T x) {
auto [a, b] = x;
return make_tuple(a, b);
}(declval<T>()));
};
template<typename T>
using to_tuple_t = typename to_tuple<T>::type;
struct Bar1
{
int x;
};
struct Bar2
{
int x;
float y;
};
int main()
{
static_assert(is_same_v<to_tuple_t<Bar1>, tuple<int>>);
static_assert(is_same_v<to_tuple_t<Bar2>, tuple<int, float>>);
}
The main issue here is that a structured bindings declaration is just that -- a declaration. We cannot form a "structured binding expression" in order to get the type, which is required in metaprogramming to constrain a template (for e.g., the void_t
pattern, or a concept
/requires
clause)
Per [dcl.struct.bnd], despite the presence of an assignment-expression, a structured binding is distinctly a declaration.
Template metaprogramming relies on types, and a declaration is without a type.
You cannot for example say decltype(int a = 10)
or even decltype(int a)
for this reason.
You can say decltype(int{})
because now we have an expression.
For this reason, your void_t
pattern does not work.
Unfortunately concepts/constraints don't help us, because we cannot have a declaration inside a requires clause (per [gram.expr])
Personally I think it's a bit of an oversight that we cannot have the equivalent of int{}
for structured bindings. But then again, reflection is on its way anyway, so the point is probably moot.
Edit: As dfri pointed out, there is a GNU extension called statement expressions that can make this possible (as an extension it is understandably not portable code)
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