I am trying to use the constructor inheritance feature of C++11. The following snippet (copied from somewhere, I don't remember whence) works completely fine:
#include <iostream>
struct Base {
Base() : Base(0) {}
Base(int a) : Base(a, 0) {}
Base(int a, double b) { std::cout << "Base(" << a << "," << b << ")" << std::endl; }
};
struct Derived : Base {
using Base::Base;
Derived(const Derived& that) = delete; // This line is the culprit
};
int main(int argc, char* argv[]) {
Derived d1;
Derived d2(42);
Derived d3(42, 3.14);
}
That is, until the line marked by the comment is added; because then all hell breaks loose:
> g++ -std=c++11 -o test test.cpp
test.cpp: In function ‘int main(int, char**)’:
test.cpp:18:11: error: no matching function for call to ‘Derived::Derived()’
Derived d1;
^
test.cpp:18:11: note: candidates are:
test.cpp:13:16: note: Derived::Derived(int)
using Base::Base;
^
test.cpp:13:16: note: candidate expects 1 argument, 0 provided
test.cpp:13:16: note: Derived::Derived(int, double)
test.cpp:13:16: note: candidate expects 2 arguments, 0 provided
It seems as if deleting the copy constructor also somehow made the default constructor from Base
inaccessible. Googling the problem didn't bring up anything useful; SO suggested this issue, but as far as I understand, I do not use copy initialization in this snippet. Could someone shed some light on what has happened here?
(The compiler that generated the message above is GCC 4.8.2; however, clang returns a similar error message.)
Whenever you define a custom constructor you need to provide a default constructor explicitly. I.e.
The problem is that marking a copy constructor with
delete
makes it user-declared, which in effect deletes the default constructor of that class (in your caseDerived
). The behaviour can be seen in this simple code:As a side remark: even if
Base::Base()
would be inherited, the compiler would see it likeDerived(): Base(){}
. ButDerived
is deleted, so it cannot really callBase::Base()
. In general, ausing Base::Base
statement is just syntactic sugar for the corresponding compiler-generatedDerived(params): Base(params){}
.Inheriting constructors doesn't get the special constructors -- empty, copy, move. This is because what you are asking for literally is almost always a bad idea.
Examine:
do you really want
derived(base const&)
to exist? Orbase(base&&)
? Both would hopelessly slicederived
.The danger of those operations happening "accidentally" means you have to bring them in explicitly if you want them.
The copy/move/default ctors, by default, happen to just call the parent version, plus the ctors of member variables. There is no need (usually) to involve inheriting them from your parent.
However, once you
=delete
,=default
or define one of these special ctors, the other ones stop being generated by the compiler. So you have to=default
the other ones, if you still want them to stick around.