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....
Uniform initialization is a feature in C++ 11 that allows the usage of a consistent syntax to initialize variables and objects ranging from primitive type to aggregates. In other words, it introduces brace-initialization that uses braces ({}) to enclose initializer values.
The base class members are already initialized by the time your derived-class constructor gets to run. You can assign them, if you have access, or call setters for them, or you can supply values for them to the base class constructor, if there is one suitable.
struct Point { int x; int y; int z; }; We can initialize an instance with the following syntax: Point p = {1, 2, 3}; This instance p then has its x equal to 1, its y equal to 2 and its z equal to 3.
Constructors in Derived Class in C++If the class “A” is written before class “B” then the constructor of class “A” will be executed first. But if the class “B” is written before class “A” then the constructor of class “B” will be executed first.
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}{}
};
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With