Search code examples
c++inheritancec++11uniform-initializationlist-initialization

Uniform initialization of derived class with trivial ctor


I'm trying to wrap my head around some corner cases with c++11 uniform initialization and I can't figure out why is this:

struct Base
{
    int x,y,z;
};

struct Derived : Base
{
};
static_assert (std::is_trivial<Base>::value, "Base must be trivial");
static_assert (std::is_trivial<Derived>::value, "Derived must be trivial");

Base b{1, 2, 3};           // 1) This compiles fine
Derived d{10, 20, 30};     // 2) This fails

Line marked 2 fails with a "no matching constructor for initialization of Derived" message both with clang 3.1 and g++ 4.7.

I can't understand why, in case of Derived, it is trying to call a constructor and not performing (I don't know how to call it, maybe aggregate initialization?) as is the case for line 1).

Something in the following reasoning is wrong?:

A) Being trivial guarantees it can be statically initialized

B) To be statically initialized no code must be executed at runtime and hence no constructor call is required A+B => why is it trying to call a constructor on a type that it knows being trivial?

I'm very confused....


Solution

  • Being trivial has nothing to do with how you can initialize something. The important bit is whether your Derived type is an aggregate, which is not the case:

    §8.5.1 [dcl.init.aggr] p1

    An aggregate is an array or a class (Clause 9) with no user-provided constructors (12.1), no brace-or-equal-initializers for non-static data members (9.2), no private or protected non-static data members (Clause 11), no base classes (Clause 10), and no virtual functions (10.3).

    Only aggregates can be initialized with aggregate initialization, so list-initialization (which is the official name for uniform initialization) can only try looking for a fitting constructor.

    What you can do is provide a constexpr constructor that forwards to the base-class, and add a defaulted default constructor:

    struct Derived : Base{
        Derived() = default;
        constexpr Derived(int a, int b, int c) : Base{a, b, c}{}
    };