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....
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 default
ed default constructor:
struct Derived : Base{
Derived() = default;
constexpr Derived(int a, int b, int c) : Base{a, b, c}{}
};