[ACCEPTED]-brace initialization for inherited pod-c++11

Accepted answer
Score: 18

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

From 20 §8.5.1 [dcl.init.aggr]

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

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

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

Score: 9

As of CPP 17 this is allowed with a slight 8 twist that you need additional {} within 7 the initializer list for each base class. Note 6 in the below example how {1,2} are enclosed 5 in "{}" and initialize i, j while 4 "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 3 works on GCC version 7.3.0 (not sure about 2 earlier versions) but fails on VS17(v 15.9.4) and VS17 with "/std:c++17" flag 1 so be mindful of your compiler support/flags.

relevant change proposal is here

Score: 0

I've been dealing with this problem today 21 and found a solution for it, though I can't 20 stress enough how dangerous this solution 19 may be (see below why it's dangerous).

My 18 particular problem was that I just wanted 17 to extend a library struct with some methods 16 of my own. I wanted to keep it POD with 15 exactly the same layout as base since I 14 wanted to use functions that take base as 13 parameter.

The solution goes like this:

#include <iostream>
using namespace std;

struct BASE {
  int x, y;
};

struct FOO: BASE {
  void Foo() { x = y = 1; }
};

int main() {
  // const declaration
  const BASE a = { 0, 1 };
  const FOO &b = *reinterpret_cast<const FOO *> (&a);

  // non-const declaration
  BASE _a = { 0, 3 };
  FOO &c = *reinterpret_cast<FOO *> (&_a);

  cout << "base: " << a.x << ", " << a.y << endl;
  cout << "foo 1: " << b.x << ", " << b.y << endl;
  cout << "foo 2: " << c.x << ", " << c.y << endl;

  return 0;
}

However, note 12 that this only works because the data layout 11 between BASE and FOO is the same. Also only 10 because I use pointers to cast to FOO type. In 9 this case the type casting is done without 8 any constructors, it just pretends that 7 the memory is in correct format. If you 6 try to reinterpret_cast without pointers, the 5 compiler will instead try to construct a 4 new object based on original.

See this answer for better 3 explanation.

Unfortunately, there doesn't 2 seem to be a nice one-liner for this. A 1 proper macro for declarations seems in order.

Score: 0

Try this;

struct A {
  float data;
  A() = default;
  A(float d) : data{d} {}
};

struct B : A {
  using A::A;
};

Test:

  A aa{1}; // OK
  B bb{1}; // OK
  std::cout << std::is_pod<A>::value << std::endl; // output 1
  std::cout << std::is_pod<B>::value << std::endl; // output 1

The output will show both 4 of A and B are POD.

When https://en.cppreference.com/w/cpp/named_req/TrivialType only says:

Has one 3 or more default constructors, all of which 2 are either trivial or deleted, and at least 1 one of which is not deleted.

It doesn't disallow custom constructors.

More Related questions