Search code examples
c++initializationc++20aggregate-initialization

Hide empty base class for aggregate initialization


Consider the following code:

struct A
{
    // No data members
    //...
};

template<typename T, size_t N>
struct B : A
{
    T data[N];
}

This is how you have to initialize B: B<int, 3> b = { {}, {1, 2, 3} }; I want to avoid the unnecessary empty {} for the base class. There is a solution proposed by Jarod42 here, however, it doesn't work with elements default initialization: B<int, 3> b = {1, 2, 3}; is fine but B<int, 3> b = {1}; is not: b.data[1] and b.data[2] aren't default initialized to 0, and a compiler error occurs. Is there any way (or there will be with c++20) to "hide" base class from construction?


Solution

  • The easiest solution is to add a variadic constructor:

    struct A { };
    
    template<typename T, std::size_t N>
    struct B : A {
        template<class... Ts, typename = std::enable_if_t<
            (std::is_convertible_v<Ts, T> && ...)>>
        B(Ts&&... args) : data{std::forward<Ts>(args)...} {}
    
        T data[N];
    };
    
    void foo() {
        B<int, 3> b1 = {1, 2, 3};
        B<int, 3> b2 = {1};
    }
    

    If you provide fewer elements in the {...} initializer list than N, the remaining elements in the array data will be value-initialized as by T().