I collected the following from several snippets, using the technique of testing the ability of aggregate-initialization, and transforming the struct into a tuple for counting the size, but when there is an array, the struct could be brace-elided and makes the structured binding incorrect. Is there any workaround/other trick for this in C++17?
struct data_t {
int a;
char b[2];
bool c;
};
// data_t could be init as {x, y1, y2, z}...
template <class T, class... Args>
decltype(void(T{std::declval<Args>()...}), std::true_type{}) test_is_braces_constructible(int);
template <class, class...>
std::false_type test_is_braces_constructible(...);
template <class T, class... TArgs>
using is_braces_constructible = decltype(test_is_braces_constructible<T, TArgs...>(0));
struct any_type {
template <class T>
constexpr operator T(); // non explicit
};
template <class T>
auto to_tuple(T &&object) noexcept
{
if constexpr (is_braces_constructible<T, any_type, any_type, any_type, any_type>{}) {
// the object coming here... the binding is incorrect
auto &&[p1, p2, p3, p4] = object;
return std::make_tuple(p1, p2, p3, p4);
} else if constexpr (is_braces_constructible<T, any_type, any_type, any_type>{}) {
auto &&[p1, p2, p3] = object;
return std::make_tuple(p1, p2, p3);
} else if constexpr (is_braces_constructible<T, any_type, any_type>{}) {
auto &&[p1, p2] = object;
return std::make_tuple(p1, p2);
} else if constexpr (is_braces_constructible<T, any_type>{}) {
auto &&[p1] = object;
return std::make_tuple(p1);
} else {
return std::make_tuple();
}
}