Search code examples
c++language-lawyerc++20aggregate-initialization

Aggregate class and non-viable constructor template


As we know, in C++20 a class that has a user-declared constructor is not aggregate.

Now, consider the following code:

#include <type_traits>

template <bool EnableCtor>
struct test {
  template <bool Enable = EnableCtor, class = std::enable_if_t<Enable>>
  test() {}
  int a;
};

int main() {
    test<false> t {.a = 0};
}

Neither GCC nor CLang compile this code. So, the class is not an aggregate, despite the fact that there is no instantiated constructor here.

Is the constructor template considered to be a "declared constructor"? What does the Standard say about such a situation?


Solution

  • The definition of aggregate has changed a lot, but the relevant part here has been pretty constant. The C++20 wording in [dcl.init.aggr] says:

    An aggregate is an array or a class ([class]) with

    • no user-declared or inherited constructors ([class.ctor]),
    • no private or protected direct non-static data members ([class.access]),
    • no virtual functions ([class.virtual]), and
    • no virtual, private, or protected base classes ([class.mi]).

    Note that it just says no declared constructors, period. Not something subtle about whether or not the constructor is viable for a particular specialization of a class template. Just none at all.

    So given something like this:

    template <bool B>
    struct X {
        int i;
        X(int i) requires B;
    };
    

    X<false> still isn't an aggregate, even though its only declared constructor isn't viable for that specialization. Doesn't matter. Aggregate-ness is a property of declarations only.