This is a two part question, one about aggregate initialization and the other about decomposition.
I have a function below doing aggregate element counting (if you want background, look here)
namespace detail
{
struct filler_t { template<class T> constexpr operator T() { return {}; } };
template<class T> concept aggregate_type = std::is_aggregate_v<T>;
}
//-------------------------------------------------------------------------
// return member count of an aggregate
template<detail::aggregate_type T>
constexpr auto aggregate_member_count(auto&& ...filler)
{
if constexpr (requires{ T{ filler... }; })
return aggregate_member_count<T>(detail::filler_t{}, filler...);
else
return sizeof...(filler) - 1;
}
I’m specifying C++23 conformance for compilers. That works as expected when counting members of a simple aggregate, but gives unexpected result for an aggregate that has a base class. In the example below it outputs “3” for class A as expected, but for class B it outputs “2”. Why is that? You can initialize B with 4 initializers.
struct A { int a; unsigned b; double c; } sa{1,2,3.};
std::cout << aggregate_member_count<A>() << "n"; // 3 - ok
struct B : A { int s; } sb{0,1,2.,3};
std::cout << aggregate_member_count<B>() << "n"; // 2?
also a decomposition of class B works in MSVC but with gcc/clang it fails with an error:
(clang) error: cannot decompose class type ‘B’: both it and its base class ‘A’ have non-static data members
Which compiler is correct?
auto [a,b,c] = sa; // ok
std::cout << a << ',' << b << ',' << c << "n";
auto [x1,x2,x3,x4] = sb; // ok - MSVC, error - clang/gcc
std::cout << x1 << ',' << x2 << ',' << x3 << ',' << x4 << "n";
Code Explorer example is here.