Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Aggregate initialization of a derived class

The following code does not compile with either Visual Studio2017 or online GDB. I expected it to compile as iterator is just a class with types and it is inherited from publicly. Is this not allowed or doesnt this work in VS2017?

template<typename T>
struct Gen : public std::iterator<std::input_iterator_tag, T>
{
    T value;
};

int main()
{   
    Gen<int> g = Gen<int>{ 10 }; // this doesnt
    Gen<int> g2 = Gen<int>{ {}, 10 }; // neither does this
}

The error is

Error C2440 'initializing': cannot convert from 'initializer list' to 'Gen'

like image 583
Serve Laurijssen Avatar asked Jan 23 '18 12:01

Serve Laurijssen


People also ask

What is aggregate initialization in C++?

An aggregate is just what it sounds like: a bunch of things clumped together. This definition includes aggregates of mixed types, like structs and classes. An array is an aggregate of a single type. Initializing aggregates can be error-prone and tedious. C++ aggregate initialization makes it much safer.

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.

What is aggregate type C++?

Formal definition from the C++ standard (C++03 8.5. 1 §1): An aggregate is an array or a class (clause 9) with no user-declared constructors (12.1), no private or protected non-static data members (clause 11), no base classes (clause 10), and no virtual functions (10.3).

How do you create a constructor from a derived class?

If we inherit a class from another class and create an object of the derived class, it is clear that the default constructor of the derived class will be invoked but before that the default constructor of all of the base classes will be invoke, i.e the order of invocation is that the base class's default constructor ...


1 Answers

What

Gen<int> g = Gen<int>{ 10 };

tries to do is calling the non-existent Gen<int>(int) constructor. What you want to do is aggregate initialization whose syntax is:

Gen<int> g = { {}, 10 };

And only works since C++17 for derived types:

If the initializer clause is a nested braced-init-list (which is not an expression), the corresponding array element/class member /public base (since C++17) is list-initialized from that clause: aggregate initialization is recursive.


For more information, aggregate initialization is defined in the following standard sections.

[dcl.init.list]/3

  1. List-initialization of an object or reference of type T is defined as follows:
    3.1 If the braced-init-list contains a designated-initializer-list, T shall be an aggregate class.

and

[dcl.init.aggr]/1

An aggregate is an array or a class (Clause 12) with
1.1 no user-provided, explicit, or inherited constructors (15.1),
1.2 no private or protected non-static data members (Clause 14),
1.3 no virtual functions (13.3), and
1.4 no virtual, private, or protected base classes (13.1).

Because in inherits from std::iterator<std::input_iterator_tag, T>.

like image 106
YSC Avatar answered Oct 01 '22 22:10

YSC