views:

111

answers:

2

take two following classes:

class Test1{
 public:
  Test1()=default;
  Test1(char in1,char in2):char1(in1),char2(in2){}
  char char1;
  char char2;
};
class Test2{
 public:
  Test2()=default;
  Test2(char in1,char in2):char1(in1),char2(in2){}
 private:
  char char1;
  char char2;
};

I know in c++0x both of these classes are considered as POD types and we can initialize objects of them using initializer lists as below:

Test1 obj1={'a','b'};//valid in c++0x
Test2 obj2={'a','b'};//valid in c++0x

But I wonder what the technical reason is that when we have different access specifiers in a class like below, it's not possible to use initializer list for initializing objects of that class and that class is not considered as a POD type ?

class Test{
 public:
  Test()=default;
  Test(char in1,char in2):char1(in1),char2(in2){}
  char char1;
 private:
  char char2;
};
Test obj={'a','b'};//invalid in c++0x

In case you don't know definition of PODs in c++0x:
A class/struct is considered a POD if it is trivial, standard-layout, and if all of its non-static members are PODs.

A trivial class or struct is defined as one that:

  1. Has a trivial default constructor. This may use the default constructor syntax (SomeConstructor() = default;).
  2. Has a trivial copy constructor, which may use the default syntax.
  3. Has a trivial copy assignment operator, which may use the default syntax.
  4. Has a trivial destructor, which must not be virtual.

A standard-layout class or struct is defined as one that:

  1. Has only non-static data members that are of standard-layout type
  2. Has the same access control (public, private, protected) for all non-static members
  3. Has no virtual functions
  4. Has no virtual base classes
  5. Has only base classes that are of standard-layout type
  6. Has no base classes of the same type as the first defined non-static member
  7. Either has no base classes with non-static members, or has no non-static data members in the most derived class and at most one base class with non-static members. In essence, there may be only one class in this class's hierarchy that has non-static members.

In case you don't know what a trivial constructor or operator is:
Compiler generates a trivial one of each of following items for a class, in case it isn't user-declared: Copy constructor, destructor and copy assignment operator.
And also if there's no user-declared constructor for a class, a trivial default constructor is generated for that class, in case there are any user-declared constructors you can use the syntax(SomeConstructor() = default;) to make your own trivial default constructor.

+3  A: 

The "technical" reason is due to the following:

Nonstatic data members of a (non-union) class with the same access control are allocated so that later members have higher addresses within a class object. The order of allocation of non-static data members with different access control is unspecified (C++0x §9.2/12).

So long as all the nonstatic data members have the same access control, their order is well-specified; otherwise their order is unspecified.

James McNellis
@James McNellis: so why doesn't compiler put initializer values in correct order since it probably knows the correct order itself ?
Pooria
@Pooria: the compiler does put initializers in the correct order. GCC warns you when it reorganizes initialization to be different than what was declared in the constructor.
caspin
@Caspin: I was talking about when there are different access specifiers and in that case, using initializer list as I mentioned, is illegal.
Pooria
@Pooria: The text I quoted is why the data members of a standard layout class must all have the same access control. Initializer lists are effectively an extension of the current aggregate initialization. I admit, though, that I haven't done much research into initializer lists; I haven't read any of the papers on them and my primary compiler (VC10) doesn't support them.
James McNellis
A: 
class Test{
 public:
  Test()=default;
  Test(char in1,char in2):char1(in1),char2(in2){}
  char char1;
 private:
  char char2;
};

considering above class following syntax is valid in c++0x:

Test obj={'a','b'};//valid in c++0x

The final proposal is here.

Pooria