Virtual inheritance and uniform initialization in C ++

Following this question about multiple (virtual) inheritance , I would like to learn about a simple MWE that does g ++ 5.2.0 upset, while clang ++ 3.6.2 handles it just fine, without any complaints even when setting -Wall and -Wextra . So here is the MWE:

 class Z {}; class A : virtual Z { protected: A() {} }; class B : virtual Z { protected: B() {} }; class C : A, B { public: C() : A{}, B{} {} }; int main() { C c{}; return 0; } 

Unlike clang ++, g ++ complains as follows:

 gccodd.c++: In constructor 'C::C()': gccodd.c++:2:34: error: 'A::A()' is protected class A : virtual Z { protected: A() {} }; ^ gccodd.c++:4:39: error: within this context class C : A, B { public: C() : A{}, B{} {} }; ^ gccodd.c++:3:34: error: 'B::B()' is protected class B : virtual Z { protected: B() {} }; ^ gccodd.c++:4:39: error: within this context class C : A, B { public: C() : A{}, B{} {} }; ^ 

Replacing uniform initialization in the C constructor with the old form works fine, although both clang ++ and g ++ are happy with the following:

 class C : A, B { public: C() : A(), B() {} }; 

This provides two obvious options:

  • The code somehow violates the standard, making the result undefined (i.e. any result will be acceptable).
  • One of the two compilers has an error related to uniform initialization and multiple + virtual inheritance.

If it is a vote question, (1) can win because icpc 15.0.0 says the following:

 gccodd.c++(4): error #453: protected function "A::A()" (declared at line 2) is not accessible through a "A" pointer or object class C : public virtual A, public virtual B { public: C() : A{}, B{} {} }; ^ gccodd.c++(4): error #453: protected function "B::B()" (declared at line 3) is not accessible through a "B" pointer or object class C : public virtual A, public virtual B { public: C() : A{}, B{} {} }; ^ 

So is it (1) or (2)? And if this is the first case, then what happened to my MWE?

+6
source share
1 answer

An initialization list of an object or link of type T is defined as follows:
(3.1) - If T is a class type, and in the list of initializers there is one element of type cv U [..]
(3.2) - Otherwise, if T is an array of characters [..]
(3.3) - Otherwise, if T is a collection, aggregate initialization (8.5.1) is performed.
(3.4) - Otherwise, if there are no elements in the list of initializers, and T is a class type with a default constructor, the object is initialized with a value.

A and B both have base classes and, therefore, are not aggregates. Therefore, the fourth paragraph applies. And so we have the same effect as we used () :

An object whose initializer is an empty set of brackets, i.e. () is initialized with a value.

Any compiler giving different results with these initializers cannot match.

ยง11.4, which handles access to protected members, does not mention anything related to the initialization form. However, regarding database initialization in the mem initializer in the constructor, ยง11.4 is currently defective, as indicated in CWG # 1883 .

+5
source

All Articles