Inheriting constructors of virtual base classes - c++

Virtual base classes are initialized in the most derived class, so my guess is that inheriting the constructor of the base class should work as well:
struct base {
base(int) {}
};
struct derived: virtual base {
using base::base;
};
derived d(0);
However, this fails to compile with GCC 5.2.0, which tries to find base::base(), but works fine with Clang 3.6.2. Is this a bug in GCC?

This is gcc bug 58751
"[C++11] Inheriting constructors do not work properly with virtual inheritance"
(aka: 63339
"using constructors" from virtual bases are implicitly deleted"):
From the 58751 description:
In the document N2540 it states that:
Typically, inheriting constructor definitions for classes with virtual bases will be ill-formed, unless the virtual base supports default initialization, or the virtual base is a direct base, and named as the base forwarded-to. Likewise, all data members and other direct bases must support default initialization, or any attempt to use a inheriting constructor will be ill-formed. Note: ill-formed when used, not declared.
Hence, the case of virtual bases is explicitly considered by the committee and thus should be implemented.
Workaround borrowed from the bug report:
struct base {
base() = default; // <--- add this
base(int) {}
};
According to the bug report, in this cases the constructor base::base(int) is called by the implicitly generated constructor derived::derived(int).
I have checked that your code does not compile. But this does and it calls the base::base(int) constructor.

Related

Why derived constructor needs base destructor?

class A{
public:
A();
private:
~A();
};
class B:public A{
public:
B(){};
private:
~B();
};
int main()
{
return 0;
}
I've got a compile error like this:
test.cpp: In constructor 'B::B()':
test.cpp:5:4: error: 'A::~A()' is private
test.cpp:10:8: error: within this context
I know the derived constructor need to invoke the base destructor, hence I set A::A() as public.
However, why the compiler complains that it need public A::~A() either?
The closest specification I could find is here - 12.4.10 class.dtor:
... A program is ill-formed if an object of class type or array
thereof is declared and the destructor for the class is not accessible
at the point of the declaration.
class B is not able to access private: ~A(), but is implicitly declaring class A because it is a base class (it is almost the same as declaring first member variable - except empty base optimization).
I am not a language lawyer and not a native speaker, but the inaccessible base class destructor seems to be the problem and the above may explain why the error points to the constructor B() (the compiler may perform the checks when they are really needed, not before).
The destructor ~A() needs to be made at least protected or B friend of A.
The C++ standards committee core working group defect report 1424 (submitted by Daniel Krügler on 2011-12-07) says:
The current specification does not appear to say whether an implementation is permitted/required/forbidden to complain when a sub-object's destructor is inaccessible.
This is fixed in C++14 by the addition of the notion of a destructor being potentially invoked. The current draft standard section 12.6.2(10) says:
In a non-delegating constructor, the destructor for each direct or virtual base class and for each non-static data member of class type is potentially invoked (12.4).
[ Note: This provision ensures that destructors can be called for fully-constructed sub-objects in case an exception is thrown (15.2). —end note ]
And in 12.4(11):
A destructor is potentially invoked if it is invoked or as specified in 5.3.4 and 12.6.2. A program is ill-formed if a destructor that is potentially invoked is deleted or not accessible from the context of the invocation.
Declare constructor and destructor as public (base class constructor anddestructor may be protected, if you ensure that is called by the subclasses only). Subclasses when constructed have base class instance created as a cubobject, so either explicit or implicit call of constructor and destructor are done

In an abstract class constructor, why I do need to call a constructor of a virtual base that will never to called?

I face the well known "dreaded" diamond situation :
A
/ \
B1 B2
\ /
C
|
D
The class A has, say the constructor A::A(int i). I also want to forbid a default instantiation of a A so I declare the default constructor of A as private.
The classes B1 and B2 are virtually derived from A and have some constructors and a protected default constructor.
[edit]
The constructors of B1 and B2 don't call the default constructor of A.
[reedit]
The default constructors of B1 and B2 don't call the default constructor of A either.
[reedit]
[edit]
The class C is an abstract class and has some constructors that don't call any of the A, B1 or B2 constructors.
In the class D, I call the constructor A::A(i) and some constructor of C.
So as expected, when D is created, it first creates a A to solve the dreaded diamond problem, then it creates B1, B2 and C. Therefore there is no call of the default constructor of A in B1, B2 and C because if there was, it would create many instances of A.
The compiler rejects the code because the default constructor of A is private. If I set it to protected it compiles.
What I don't understand is that when I run the code, the default constructor of A is never called (as it should be). So why doesn't the compiler allow me to set it as private?
[edit]
okay I'll write an example... but it hurts ;-)
class A{
public:
A(int i):i_(i){};
virtual ~A(){};
protected:
int i_;
private:
A():i_(0){};/*if private => compilation error, if protected => ok*/
};
class B1: public virtual A{
public:
B1(int i):A(i){};
virtual ~B1(){};
protected:
B1():A(0){};
};
class B2: public virtual A{
public:
B2(int i):A(i){};
virtual ~B2(){};
protected:
B2():A(0){};
};
class C: public B1, public B2{
public:
C(int j):j_(j){};
virtual ~C()=0;
protected:
int j_;
};
C::~C(){};
class D: public C{
public:
D(int i,int j):A(i),C(j){};
~D(){};
};
int main(){
D d(1,2);
}
The compiler says that in constructor of C, A::A() is private. I agree with this, but as C is an abstract class, it can't be instantiated as a complete object (but it can be instantiated as a base class subobject, by instantiating a D).
[edit]
I added the tag `language-lawer' on someone's recommendation.
C++ doesn't have an access control specifier for member functions that can only be called from a derived class, but a constructor for an abstract class can only be called from a derived class by definition of an abstract class.
The compiler cannot know in advance exactly which classes are instantiated (this is a runtime property), and it cannot know which constructors are potentially called before link-time.
The standard text (emphasis mine):
All sub-objects representing virtual base classes are initialized by
the constructor of the most derived class (1.8 [intro.object]). If the
constructor of the most derived class does not specify a
mem-initializer for a virtual base class V, then V's default
constructor is called to initialize the virtual base class subobject.
If V does not have an accessible default constructor, the
initialization is ill-formed. A mem-initializer naming a virtual base
class shall be ignored during execution of the constructor of any
class that is not the most derived class.
1) It makes no exception for abstract classes and can only be interpreted as saying that all constructors should do a (sometimes fake) attempt at calling virtual base constructors.
2) It says that at runtime such attempts are ignored.
Some committee members have stated a different opinion in DR 257:
Abstract base constructors and virtual base initialization
Section: 12.6.2 [class.base.init] Status: CD2 Submitter: Mike
Miller Date: 1 Nov 2000 [Voted into WP at October, 2009 meeting.]
Must a constructor for an abstract base class provide a
mem-initializer for each virtual base class from which it is directly
or indirectly derived? Since the initialization of virtual base
classes is performed by the most-derived class, and since an abstract
base class can never be the most-derived class, there would seem to be
no reason to require constructors for abstract base classes to
initialize virtual base classes.
It is not clear from the Standard whether there actually is such a
requirement or not. The relevant text is found in 12.6.2
[class.base.init] paragraph 6:
(...quoted above)
This paragraph requires only that the most-derived class's constructor
have a mem-initializer for virtual base classes. Should the silence be
construed as permission for constructors of classes that are not the
most-derived to omit such mem-initializers?
There is no "silence". The general rule applies as there is no specific rule for abstract classes.
Christopher Lester, on comp.std.c++, March 19, 2004: If any of you
reading this posting happen to be members of the above working group,
I would like to encourage you to review the suggestion contained
therein, as it seems to me that the final tenor of the submission is
both (a) correct (the silence of the standard DOES mandate the
omission) and (b) describes what most users would intuitively expect
and desire from the C++ language as well.
The suggestion is to make it clearer that constructors for abstract
base classes should not be required to provide initialisers for any
virtual base classes they contain (as only the most-derived class has
the job of initialising virtual base classes, and an abstract base
class cannot possibly be a most-derived class).
The suggestion cannot make "clearer" something that doesn't exist now.
Some committee members are taken their desire for reality and it is very wrong.
(snip example and discussion similar to OP's code)
Proposed resolution (July, 2009):
Add the indicated text (moved from paragraph 11) to the end of 12.6.2
[class.base.init] paragraph 7:
...The initialization of each base and member constitutes a
full-expression. Any expression in a mem-initializer is evaluated as
part of the full-expression that performs the initialization. A
mem-initializer where the mem-initializer-id names a virtual base
class is ignored during execution of a constructor of any class that
is not the most derived class.
Change 12.6.2 [class.base.init]
paragraph 8 as follows:
If a given non-static data member or base class is not named by a
mem-initializer-id (including the case where there is no
mem-initializer-list because the constructor has no ctor-initializer)
and the entity is not a virtual base class of an abstract class (10.4
[class.abstract]), then
if the entity is a non-static data member that has a
brace-or-equal-initializer, the entity is initialized as specified in
8.5 [dcl.init];
otherwise, if the entity is a variant member (9.5 [class.union]), no
initialization is performed;
otherwise, the entity is default-initialized (8.5 [dcl.init]).
[Note: An abstract class (10.4 [class.abstract]) is never a most
derived class, thus its constructors never initialize virtual base
classes, therefore the corresponding mem-initializers may be omitted.
—end note] After the call to a constructor for class X has
completed...
Change 12.6.2 [class.base.init] paragraph 10 as follows:
Initialization shall proceed proceeds in the following order:
First, and only for the constructor of the most derived class as
described below (1.8 [intro.object]), virtual base classes shall be
are initialized in the order they appear on a depth-first
left-to-right traversal of the directed acyclic graph of base classes,
where “left-to-right” is the order of appearance of the base class
names in the derived class base-specifier-list.
Then, direct base classes shall be are initialized in declaration
order as they appear in the base-specifier-list (regardless of the
order of the mem-initializers).
Then, non-static data members shall be are initialized in the order
they were declared in the class definition (again regardless of the
order of the mem-initializers).
Finally, the compound-statement of the constructor body is executed.
[Note: the declaration order is mandated to ensure that base and
member subobjects are destroyed in the reverse order of
initialization. —end note]
Remove all normative text in 12.6.2 [class.base.init] paragraph 11,
keeping the example:
All subobjects representing virtual base classes are initialized by
the constructor of the most derived class (1.8 [intro.object]). If the
constructor of the most derived class does not specify a
mem-initializer for a virtual base class V, then V's default
constructor is called to initialize the virtual base class subobject.
If V does not have an accessible default constructor, the
initialization is ill-formed. A mem-initializer naming a virtual base
class shall be ignored during execution of the constructor of any
class that is not the most derived class. [Example:...
The DR is marked "CD2": the committee agrees this was an issue and the language definition is changed to fix this issue.

Inheriting constructors and virtual base classes

I'm about to create an exception class hierarchy which conceptually looks somewhat like this:
#include <iostream>
#include <stdexcept>
class ExceptionBase : public std::runtime_error {
public:
ExceptionBase( const char * msg ) : std::runtime_error(msg) {}
};
class OperationFailure : virtual public ExceptionBase {
public:
using ExceptionBase::ExceptionBase;
};
class FileDoesNotExistError : virtual public ExceptionBase {
public:
using ExceptionBase::ExceptionBase;
};
class OperationFailedBecauseFileDoesNotExistError
: public OperationFailure, FileDoesNotExistError {
public:
using ExceptionBase::ExceptionBase; // does not compile
};
int main() {
OperationFailedBecauseFileDoesNotExistError e("Hello world!\n");
std::cout << e.what();
}
All constructors should look the same as the constructor of the ExceptionBase class. The derived exceptions only differ concerning their type, there's no added functionality otherwise. The last exception type mentioned in the above code should also have these constructors. Is this possible using the inheriting constructors feature of the C++11 standard? If that is not possible: what are alternatives?
(By the way: In the above code the classes OperationFailure and FileDoesNotExistError did not compile with gcc 4.8, but with clang 3.4. Apparently, gcc rejects inheriting constructors for virtual bases. It would be interesting to know who's right here. Both compilers rejected the class OperationFailedBecauseFileDoesNotExistError, because the inheriting constructor does not inherit from a direct base.)
When the using-declaration is used to inherit constructors, it requires a direct base class [namespace.udecl]/3
If such a using-declaration names a constructor, the nested-name-specifier shall name a direct base class of the class being defined; otherwise it introduces the set of declarations found by member name lookup.
I.e. in your case, the using-declaration in OperationFailedBecauseFileDoesNotExistError doesn't inherit, but re-declares (as an alias), or unhides, the name of the ctor of ExceptionBase.
You'll have to write a non-inheriting ctor for OperationFailedBecauseFileDoesNotExistError.
By the way, this is fine for non-virtual base classes: The using-declaration for inheriting ctors is rewritten as:
//using ExceptionBase::ExceptionBase;
OperationFailure(char const * msg)
: ExceptionBase( static_cast<const char*&&>(msg) )
{}
As you may only initialize a direct base class (or virtual base class) in the mem-initializer-list, it makes sense for non-virtual base classes to restrict the using-declaration to inherit ctors only from direct base classes.
The authors of the inheriting ctors proposal have been aware that this breaks support for virtual base class ctors, see N2540:
Typically, inheriting constructor definitions for classes with virtual bases will be ill-formed, unless the virtual base supports default initialization, or the virtual base is a direct base, and named as the base forwarded-to. Likewise, all data members and other direct bases must support default initialization, or any attempt to use a inheriting constructor will be ill-formed. Note: ill-formed when used, not declared.
Inhering constructors is like introducing wrapper functions for all the constructors you have specified. In your case, you must call the specific constructors of both OperationFailure and FileDoesNotExistError but the introduced wrappers will only call either of them.
I just checked the latest C++11 draft (section 12.9) but it doesn't really explicitly cover your case.

Virtual inheritance vs. non-default constructors

This code is rejected by (at least) MSVC, ICC, and GCC:
class A {
public:
A( int ) { }
};
class B: virtual public A {
public:
//B(): A( -1 ) { } // uncomment to make it compilable
virtual void do_something() = 0;
};
class C: public B {
public:
C(): A( 1 ) { }
virtual void do_something() { }
};
int main() {
C c;
return 0;
}
on the basis of
error : no default constructor exists for class "A"
class B: virtual public A {
^
detected during implicit generation of "B::B()" at line 14
Questions:
If the code is indeed invalid, how exactly does this follow from
the standard? AFAICT, 10.4/2 and 1.8/4 taken together imply that B
cannot be a type of the most derived class, and therefore from
12.6.2/10 we have that B can never, ever call A's constructors.
(The section numbers are for C++11.)
If the code is valid, are compilers violating the standard by
requiring the presence of constructors they could not possibly call?
Note that not only they want to call A::A() from B::B(), but they
want to do it while compiling C::C() (double weird).
P.S. This was originally asked on the ICC forum, but posted here due to not being limited to this compiler (and no details forthcoming).
Clang shows the error as:
error: call to implicitly-deleted default constructor of 'B'
C(): A( 1 ) { }
^
12.1/5 says "A defaulted default constructor for class X is defined as deleted if [...] any [...] virtual base class [...] has class type M [...] and [...] M has no default constructor [...]."
I think you are trying to derive a "theorem" from the facts that can be found in the standard, and then you expect the standard to acknowledge the existence of that "theorem". The standard does not do that. It doesn't strive to find and incorporate all possible "theorems" that can be derived from the standard text.
Your "theorem" is perfectly valid (unless I'm missing something). You are right, since class B is abstract, this class can never be used as a most derived class. This immediately means that class B will never get a chance to construct its virtual base A. And that means that technically in B the compiler should not care about the availability, and/or accessibility of the appropriate constructors in A or in any other virtual bases.
But the standard simply does not make that connection and does not care to make it. It doesn't treat constructors of abstract classes in any special way. The requirements imposed on such constructors are the same as for non-abstract classes.
You can call try suggesting it as a possible improvement to the standard committee.
It looks like 12.6.2/4 prohibits this to me:
If a given nonstatic data member or base class is not named by a
mem-initializer-id (including the case where there is no
mem-initializer-list because the constructor has no ctor-initializer),
then
— If the entity is a nonstatic data member of (possibly
cv-qualified) class type (or array thereof) or a base class, and the
entity class is a non-POD class, the entity is default-initialized
(8.5)...
It looks to me like that regardless of the class being a virtual base, B's default constructor is still synthesized by the compiler, and such default constructor doesn't know how to construct its A base ("the entity is default-initialized (8.5)").

MSVC9.0 bug or misunderstanding of virtual inheritance and friends?

consider the following code:
class A
{
friend class B;
friend class C;
};
class B: virtual private A
{
};
class C: private B
{
};
int main()
{
C x; //OK default constructor generated by compiler
C y = x; //compiler error: copy-constructor unavailable in C
y = x; //compiler error: assignment operator unavailable in C
}
The MSVC9.0 (the C++ compiler of Visual Studio 2008) does generate the default constructor but is unable to generate copy and assignment operators for C although C is a friend of A. Is this the expected behavior or is this a Microsoft bug? I think the latter is the case, and if I am right, can anyone point to an article/forum/... where this issue is discussed or where microsoft has reacted to this bug. Thank you in advance.
P.S. Incidentally, if BOTH private inheritances are changed to protected, everything works
P.P.S. I need a proof, that the above code is legal OR illegal. It was indeed intended that a class with a virtual private base could not be derived from, as I understand. But they seem to have missed the friend part. So... here it goes, my first bounty :)
The way I interpret the Standard, the sample code is well-formed. (And yes, the friend declarations make a big difference from the thing #Steve Townsend quoted.)
11.2p1: If a class is declared to be a base class for another class using the private access specifier, the public and protected members of the base class are accessible as private members of the derived class.
11.2p4: A member m is accessible when named in class N if
m as a member of N is public, or
m as a member of N is private, and the reference occurs in a member or friend of class N, or
m as a member of N is protected, and the reference occurs in a member or friend of class N, or in a member or friend of a class P derived from N, where m as a member of P is private or protected, or
there exists a base class B of N that is accessible at the point of reference, and m is accessible when named in class B.
11.4p1: A friend of a class is a function or class that is not a member of the class but is permitted to use the private and protected member names from the class.
There are no statements in Clause 11 (Member access control) which imply that a friend of a class ever has fewer access permissions than the class which befriended it. Note that "accessible" is only defined in the context of a specific class. Although we sometimes talk about a member or base class being "accessible" or "inaccessible" in general, it would be more accurate to talk about whether it is "accessible in all contexts" or "accessible in all classes" (as is the case when only public is used).
Now for the parts which describe checks on access control in automatically defined methods.
12.1p7: An implicitly-declared default constructor for a class is implicitly defined when it is used to create an object of its class type (1.8). The implicitly-defined default constructor performs the set of initializations of the class that would be performed by a user-written default constructor for that class with an empty mem-initializer-list (12.6.2) and an empty function body. If that user-written default constructor would be ill-formed, the program is ill-formed.
12.6.2p6: All sub-objects representing virtual base classes are initialized by the constructor of the most derived class (1.8). If the constructor of the most derived class does not specify a mem-initializer for a virtual base class V, then V's default constructor is called to initialize the virtual base class subobject. If V does not have an accessible default constructor, the initialization is ill-formed.
12.4p5: An implicitly-declared destructor is implicitly defined when it is used to destroy an object of its class type (3.7). A program is ill-formed if the class for which a destructor is implicitly defined has:
a non-static data member of class type (or array thereof) with an inaccessible destructor, or
a base class with an inaccessible destructor.
12.8p7: An implicitly-declared copy constructor is implicitly defined if it is used to initialize an object of its class type from a copy of an object of its class type or of a class type derived from its class type. [Note: the copy constructor is implicitly defined even if the implementation elided its use (12.2).] A program is ill-formed if the class for which a copy constructor is implicitly defined has:
a nonstatic data member of class type (or array thereof) with an inaccessible or ambiguous copy constructor, or
a base class with an inaccessible or ambiguous copy constructor.
12.8p12: A program is ill-formed if the class for which a copy assignment operator is implicitly defined has:
a nonstatic data member of const type, or
a nonstatic data member of reference type, or
a nonstatic data member of class type (or array thereof) with an inaccessible copy assignment operator, or
a base class with an inaccessible copy assignment operator.
All these requirements mentioning "inaccessible" or "accessible" must be interpreted in the context of some class, and the only class that makes sense is the one for which a member function is implicitly defined.
In the original example, class A implicitly has public default constructor, destructor, copy constructor, and copy assignment operator. By 11.2p4, since class C is a friend of class A, all those members are accessible when named in class C. Therefore, access checks on those members of class A do not cause the implicit definitions of class C's default constructor, destructor, copy constructor, or copy assignment operator to be ill-formed.
Your code compiles fine with Comeau Online, and also with MinGW g++ 4.4.1.
I'm mentioning that just an "authority argument".
From a standards POV access is orthogonal to virtual inheritance. The only problem with virtual inheritance is that it's the most derived class that initializes the virtually-derived-from class further up the inheritance chain (or "as if"). In your case the most derived class has the required access to do that, and so the code should compile.
MSVC also has some other problems with virtual inheritance.
So, yes,
the code is valid, and
it's an MSVC compiler bug.
FYI, that bug is still present in MSVC 10.0. I found a bug report about a similar bug, confirmed by Microsoft. However, with just some cursory googling I couldn't find this particular bug.
Classes with virtual private base should not be derived from, per this at the C++ SWG. The compiler is doing the right thing (up to a point). The issue is not with the visibility of A from C, it's that C should not be allowed to be instantiated at all, implying that the bug is in the first (default) construction rather than the other lines.
Can a class with a private virtual base class be derived from?
Section: 11.2 [class.access.base]
Status: NAD Submitter: Jason
Merrill Date: unknown
class Foo { public: Foo() {} ~Foo() {} };
class A : virtual private Foo { public: A() {} ~A() {} };
class Bar : public A { public: Bar() {} ~Bar() {} };
~Bar() calls
~Foo(), which is ill-formed due to
access violation, right? (Bar's
constructor has the same problem since
it needs to call Foo's constructor.)
There seems to be some disagreement
among compilers. Sun, IBM and g++
reject the testcase, EDG and HP accept
it. Perhaps this case should be
clarified by a note in the draft. In
short, it looks like a class with a
virtual private base can't be derived
from.
Rationale: This is what was intended.
btw the Visual C++ v10 compiler behaviour is the same as noted in the question. Removing virtual from the inheritance of A in B fixes the problem.