In this piece of code, why is A's constructor with no parameters not inherited? Is there a special rule that prevents inheriting constructors with no parameters?
struct A {
A(void *) {}
A() {}
};
class B : public A {
public:
using A::A;
B(int x) {}
};
void f() {
B b(1);
B b2(nullptr);
B b3; // error
}
clang++ -std=c++11 gives this error, and g++ -std=c++11 gives a substantially similar error message:
td.cpp:15:7: error: no matching constructor for initialization of 'B'
B b3; // error
^
td.cpp:9:5: note: candidate constructor not viable: requires single argument 'x', but no arguments
were provided
B(int x) {}
^
td.cpp:8:14: note: candidate constructor (inherited) not viable: requires 1 argument, but 0 were
provided
using A::A;
^
td.cpp:2:5: note: inherited from here
A(void *) {}
The relevant information is in 12.9 [class.inhctor] paragraph 3 (the highlighting is added):
For each non-template constructor in the candidate set of inherited constructors other than a constructor having no parameters or a copy/move constructor having a single parameter, a constructor is implicitly declared with the same constructor characteristics unless there is a user-declared constructor with the same signature in the complete class where the using-declaration appears. [...]
That is, default constructor are not inherited unless they have a [defaulted] argument. If they have a default argument they are inherited but without the defaulted argument as is pointed out by a node on the same paragraph:
Note: Default arguments are not inherited. [...]
Basically, that says that default constructors are not inherited.
there is no constructor in B with no parameters, try
B() : A(){}
Related
I'm trying to inherit constructors from the base class and define an additional constructor in the derived class.
#include <iostream>
#define BREAK_THIS_CODE 1
class Base
{
public:
Base()
{
std::cout << "Base " << "\n";
}
Base(int i)
{
std::cout << "Base " << i << "\n";
}
};
class Derived : public Base
{
public:
using Base::Base;
#if BREAK_THIS_CODE
Derived(int i, int j)
{
std::cout << "Derived " << i << " " << j << "\n";
}
#endif
};
int main()
{
Derived d1(10);
Derived d2; // error C2512: 'Derived': no appropriate default constructor available
return 0;
}
Adding Derived(int, int) seems to delete Base() but Base(int) is unaffected by this. Why is the default constructor getting removed? I expected Derived to have a total of three user-defined constructors. The only thing I can think of is the inherited Base() constructor is being treated as an implicitly-declared default constructor and adding an extra constructor is deleting the default constructor.
I've tried this on VS2015 and get the following error:
1> main.cpp
1>main.cpp(37): error C2512: 'Derived': no appropriate default constructor available
1> main.cpp(19): note: see declaration of 'Derived'
Also tried this example on Coliru: http://coliru.stacked-crooked.com/a/790b540c44dccb9f
clang++ -std=c++11 -O3 -pedantic -pthread main.cpp && ./a.out
main.cpp:35:10: error: no matching constructor for initialization of 'Derived'
Derived d2;
^
main.cpp:22:14: note: candidate constructor (inherited) not viable: requires 1 argument, but 0 were provided
using Base::Base;
^
main.cpp:13:2: note: inherited from here
Base(int i)
^
main.cpp:19:7: note: candidate constructor (the implicit copy constructor) not viable: requires 1 argument, but 0 were provided
class Derived : public Base
^
main.cpp:19:7: note: candidate constructor (the implicit move constructor) not viable: requires 1 argument, but 0 were provided
main.cpp:25:2: note: candidate constructor not viable: requires 2 arguments, but 0 were provided
Derived(int i, int j)
^
1 error generated.
Per CppReference:
If the using-declaration refers to a constructor of a direct base of the class being defined (e.g. using Base::Base;), constructors of that base class are inherited, according to the following rules:
1) A set of candidate inheriting constructors is composed of
[rules here]
2) All candidate inherited constructors that aren't the default constructor or the copy/move constructor and whose signatures do not match user-defined constructors in the derived class, are implicitly declared in the derived class. The default parameters are not inherited
So you cannot inherit a default constructor. When a class has declared a user-defined constructor, the compiler does not generate a default constructor for that class, unless you explicitly ask for one using Derived() = default. When you remove your user-defined constructor, the compiler can then generate a default constructor for you.
I've been searching for this and I'm amazed I haven't found anything. Why can't I inherit a base class constructor using using declaration and add an overload in the derived class? I'm using Visual C++ 2013, the base class constructor is ignored when default-constructing b:
error C2512: 'B' : no appropriate default constructor available
I've dealt with this by re-defining the constructors, but I don't like that. This is just a minimal example, it wouldn't bother me if I had only one base class constructor.
struct A
{
A() : a(10) {}
int a;
};
struct B : A
{
using A::A;
explicit B(int a) { this->a = a; }
};
int main()
{
B b;
}
The problem is that default-constructors are not inherited. From [class.inhctor]/p3:
For each non-template constructor in the candidate set of inherited constructors [..], a constructor is implicitly declared with the same constructor characteristics unless there is a user-declared constructor with the same signature in the complete class where the using-declaration appears or the constructor would be a default, copy, or move constructor for that class.
You also have a user-declared constructor that suppresses the creation of an implicit default-constructor. Just add a defaulted one to make it work:
B() = default;
I've been searching for this and I'm amazed I haven't found anything. Why can't I inherit a base class constructor using using declaration and add an overload in the derived class? I'm using Visual C++ 2013, the base class constructor is ignored when default-constructing b:
error C2512: 'B' : no appropriate default constructor available
I've dealt with this by re-defining the constructors, but I don't like that. This is just a minimal example, it wouldn't bother me if I had only one base class constructor.
struct A
{
A() : a(10) {}
int a;
};
struct B : A
{
using A::A;
explicit B(int a) { this->a = a; }
};
int main()
{
B b;
}
The problem is that default-constructors are not inherited. From [class.inhctor]/p3:
For each non-template constructor in the candidate set of inherited constructors [..], a constructor is implicitly declared with the same constructor characteristics unless there is a user-declared constructor with the same signature in the complete class where the using-declaration appears or the constructor would be a default, copy, or move constructor for that class.
You also have a user-declared constructor that suppresses the creation of an implicit default-constructor. Just add a defaulted one to make it work:
B() = default;
I've been searching for this and I'm amazed I haven't found anything. Why can't I inherit a base class constructor using using declaration and add an overload in the derived class? I'm using Visual C++ 2013, the base class constructor is ignored when default-constructing b:
error C2512: 'B' : no appropriate default constructor available
I've dealt with this by re-defining the constructors, but I don't like that. This is just a minimal example, it wouldn't bother me if I had only one base class constructor.
struct A
{
A() : a(10) {}
int a;
};
struct B : A
{
using A::A;
explicit B(int a) { this->a = a; }
};
int main()
{
B b;
}
The problem is that default-constructors are not inherited. From [class.inhctor]/p3:
For each non-template constructor in the candidate set of inherited constructors [..], a constructor is implicitly declared with the same constructor characteristics unless there is a user-declared constructor with the same signature in the complete class where the using-declaration appears or the constructor would be a default, copy, or move constructor for that class.
You also have a user-declared constructor that suppresses the creation of an implicit default-constructor. Just add a defaulted one to make it work:
B() = default;
I'm trying to compile the following simple code using g++ 4.9.0:
struct A {
explicit A(int x) { }
};
struct B : public virtual A {
using A::A;
};
int main(int argc, char** argv) {
B b(0);
return 0;
}
But I get the following error:
$ g++ -std=c++11 main.cpp
main.cpp: In function ‘int main(int, char**)’:
main.cpp:10:10: error: use of deleted function ‘B::B(int)’
B b(0);
^
main.cpp:6:14: note: ‘B::B(int)’ is implicitly deleted because the default definition would be ill-formed:
using A::A;
^
main.cpp:6:14: error: no matching function for call to ‘A::A()’
main.cpp:6:14: note: candidates are:
main.cpp:2:14: note: A::A(int)
explicit A(int x) { }
^
main.cpp:2:14: note: candidate expects 1 argument, 0 provided
main.cpp:1:8: note: constexpr A::A(const A&)
struct A {
^
main.cpp:1:8: note: candidate expects 1 argument, 0 provided
main.cpp:1:8: note: constexpr A::A(A&&)
main.cpp:1:8: note: candidate expects 1 argument, 0 provided
Am I doing something wrong? Is it a compiler bug?
This is a GCC bug. §7.3.3 [namespace.udecl]/p3 requires that
In a using-declaration used as a member-declaration, the
nested-name-specifier shall name a base class of the class being defined. If such a using-declaration names a constructor, the
nested-name-specifier shall name a direct base class of the class being defined...
A is a direct base of B, so using A::A; is allowed.
The standard specifies that (§12.9 [class.inhctor]/p8):
An implicitly-defined inheriting constructor performs the set of
initializations of the class that would be performed by a user-written
inline constructor for that class with a mem-initializer-list whose
only mem-initializer has a mem-initializer-id that names the base
class denoted in the nested-name-specifier of the using-declaration
and an expression-list as specified below, and where the
compound-statement in its function body is empty (12.6.2). If that
user-written constructor would be ill-formed, the program is
ill-formed. Each expression in the expression-list is of the form
static_cast<T&&>(p), where p is the name of the corresponding
constructor parameter and T is the declared type of p.
Thus the corresponding user-written constructor is
B::B(int x) : A(static_cast<int&&>(x)) { }
which is well-formed.
It appears to compile with clang, but not gcc (at least on my machine). Even with, gcc, however, the code compiles and works fine if you simply add a explicit A() constructor to the base class.
EDIT Apparently, as pointed out in the comment by #T.C., this is a known bug in GCC.