Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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....

like image 854
abigagli Avatar asked Nov 29 '12 12:11

abigagli


People also ask

What is uniform initialization?

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.

Can derived class initialize base member?

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.

How do you initialize a class structure in C++?

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.

How do you create a derived class constructor in C++?

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.


1 Answers

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}{}
};
like image 95
Xeo Avatar answered Nov 09 '22 22:11

Xeo