Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

brace initialization for inherited pod

Tags:

c++

c++11

#include <iostream>
#include <type_traits>


struct base_pod_t {
    unsigned x;
};

struct der_pod_t : public base_pod_t { };

int main()
{
    std::cout << "base_pod_t is POD: " << std::is_pod<base_pod_t>::value << std::endl;
    std::cout << "der_pod_t  is POD: " << std::is_pod<der_pod_t>::value << std::endl;
    base_pod_t b1 = {};     // OK
    base_pod_t b2 = {3};    // OK

    der_pod_t p1 = {};      // OK
//    der_pod_t p2 = {4};   // ERROR!
}

Last line results in error. How can I brace initialize der_pod_t with value?


It seems that even though it's a POD it tries to use constructor?


EDIT: As @Praetorian and @dyb suggested it is a POD thus result of std::is_pod<der_pod_t>::value is correct.

like image 270
name Avatar asked May 22 '14 13:05

name


2 Answers

base_pod_t is an aggregate and the initialization you're performing is aggregate initialization.

From §8.5.1 [dcl.init.aggr]

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

2 When an aggregate is initialized by an initializer list, as specified in 8.5.4, the elements of the initializer list are taken as initializers for the members of the aggregate, in increasing subscript or member order. Each member is copy-initialized from the corresponding initializer-clause. ...

However, der_pod_t is not an aggregate because it has a base class. It's a POD, and the same rules for list initialization do not apply. Now, when the compiler sees a non-empty braced-init-list it'll first search for a constructor that takes an initializer_list. If none are found it then attempts to match other constructors of the class. Since der_pod_t has no constructors that take a single int as argument, the error occurs.

like image 178
Praetorian Avatar answered Oct 09 '22 22:10

Praetorian


As of CPP 17 this is allowed with a slight twist that you need additional {} within the initializer list for each base class. Note in the below example how {1,2} are enclosed in "{}" and initialize i, j while "3" initializes derived k.

struct base_pod
{
    int i, j;

};

struct der_pod : public base_pod
{
    int k;
};

der_pod dp{ {1 , 2}, 3 };

This works on GCC version 7.3.0 (not sure about earlier versions) but fails on VS17(v 15.9.4) and VS17 with "/std:c++17" flag so be mindful of your compiler support/flags.

relevant change proposal is here

like image 45
David Avatar answered Oct 09 '22 21:10

David