Why can't I inherit the constructors of a virtual base? - c++

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.

Related

Passing arguments into a struct in c++ 11 [duplicate]

struct SS {int a; int s;};
int main ()
{
vector<SS> v;
v.push_back(SS{1, 2});
}
The code can be compiled without any error. However, when the struct is initialized in class, I got compilation error. Can anyone explain it?
struct SS {int a = 0; int s = 2;};
Error:
In function ‘int main()’:
error: no matching function for call to ‘SS::SS(<brace-enclosed initializer list>)’
v.push_back(SS{1, 2});
^
note: candidates are:
note: constexpr SS::SS()
struct SS {int a = 0; int s = 2;};
^
note: candidate expects 0 arguments, 2 provided
note: constexpr SS::SS(const SS&)
note: candidate expects 1 argument, 2 provided
note: constexpr SS::SS(SS&&)
note: candidate expects 1 argument, 2 provided
In C++11, when you use non static data member initialization at the point of declaration like you do here:
struct SS {int a = 0; int s = 2;};
you make the class a non-aggregate. This means you can no longer initialize an instance like this:
SS s{1,2};
To make this initialization syntax work for a non-aggregate, you would have to add a two-parameter constructor:
struct SS
{
SS(int a, int s) : a(a), s(s) {}
int a = 0;
int s = 2;
};
This restriction has been lifted in C++14.
Note that you may want to add a default constructor for the class. The presence of a user-provided constructor inhibits the compiler generated default one.
See related reading here.
Use of a default member initializer renders the class/struct a non-aggregate:
§ 8.5.1 Aggregates
An aggregate is an array or a class (Clause 9) with no user-provided constructors (12.1), no brace-or-equal-initializers for non-static data members (9.2), no private or protected non-static data members (Clause 11), no base classes (Clause 10), and no virtual functions (10.3).
Semantics differ for aggregates and non-aggregates:
Aggregates (e.g., arrays and structs):
Initialize members/elements beginning-to-end.
Non-aggregates:
Invoke a constructor.
v.push_back(SS{1, 2}); // Error, it tries to call SS constructor
Which means you need a constructor now:
struct SS
{
SS(int a, int s) : a(a), s(s)
{
}
int a = 0;
int s = 2;
};
I had the same problem. In my case, I had two structs that both had a few constructors, including copy constructors, inheriting from an abstract parent.
When the advice above didn't help, I finally realized I needed to remove explicit specifier from the copy constructors and that removed the error.
Thought I would share in case another poor soul spends as long finding this mistake as I just did.

Compiler offers private constructor as a candidate in program code

#include <iostream>
using namespace std;
class Test{
private:
Test(int a, int b=0)
{
cout << "private constructor\n";
}
public:
Test(int a)
{
cout << "public constructor\n";
}
};
int main()
{
Test t(1);
}
When I attempted to compile the code gcc says:
test.cpp: In function ‘int main()’:
test.cpp:20:10: error: call of overloaded ‘Test(int)’ is ambiguous
Test t(1);
^
test.cpp:12:2: note: candidate: Test::Test(int)
Test(int a)
^
test.cpp:7:2: note: candidate: Test::Test(int, int)
Test(int a, int b=0)
^
test.cpp:5:7: note: candidate: Test::Test(const Test&)
class Test{
^
and clang says:
test.cpp:20:7: error: call to constructor of 'Test' is ambiguous
Test t(1);
^ ~
test.cpp:7:2: note: candidate constructor
Test(int a, int b=0)
^
test.cpp:12:2: note: candidate constructor
Test(int a)
^
test.cpp:5:7: note: candidate is the implicit copy constructor
class Test{
^
1 error generated.
What is the reason of the ambiguity? Since Test(int,int) is private, it shouldn't be possible to call it in Test t(1). A possible answer is (what I thought initially), it makes two identical signatures of constructors possible, i.e Test() can be called with only one int in private constructor. But in the program code Test t(1) is only feasible for public constructors, so it shouldn't offer the private constructor as a candidate. Why does it say that?
It's ambiguous for an explicit reason, as according to the standard:
[class.access/5]
It should be noted that it is access to members and base classes that
is controlled, not their visibility. Names of members are still
visible, and implicit conversions to base classes are still
considered, when those members and base classes are inaccessible. The
interpretation of a given construct is established without regard to
access control. If the interpretation established makes use of
inaccessible member names or base classes, the construct is
ill-formed.
And that visibility means that the compiler must consider both overloads for the construction, and they are equally good for the argument you passed.
Since the constructor is private, and therefore only accessible withing the scope of the class and its members, just remove the default parameter value. You can maintain this default value in your classes definition in other ways. For instance, by introducing a constant in the classes implementation file:
int const default_b = 0;
// ...
return Test{a, default_b};

Constructor nominated by using declaration

I'm trying to declare a member name which is constructor of base class as the following:
#include <iostream>
class A{ };
class B: public A
{
using A::A; //error: ‘A::A’ names constructor
};
int main()
{
}
Where is it specified that constructor cannot be accepted by using declaration? I'm looking for a corresponding quote from the Standard.
Where is it specified that constructor cannot be accepted by using declaration?
Nowhere, because it can. See 12 Special Member Functions:
12.9 Inheriting constructors [class.inhctor]
A using-declaration (7.3.3) that names a constructor implicitly declares a set of
inheriting constructors. The candidate set of inherited constructors from the class X named in the using-declaration consists of actual constructors and notional constructors that result from the transformation of defaulted parameters as follows:
— all non-template constructors of X, and
— for each non-template constructor of X that has at least one parameter with a default argument, the set of constructors that results from omitting any ellipsis parameter specification and successively omitting parameters with a default argument from the end of the parameter-type-list, and
— all constructor templates of X, and
— for each constructor template of X that has at least one parameter with a default argument, the set of constructor templates that results from omitting any ellipsis parameter specification and successively omitting parameters with a default argument from the end of the parameter-type-list.
....
Here's an example:
struct A
{
explicit A(int) {}
};
struct B: A
{
using A::A;
};
int main()
{
B b{42};
}

C++11 constructor inheritance and constructors with no parameters

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(){}

c++11 struct initialization compilation error

struct SS {int a; int s;};
int main ()
{
vector<SS> v;
v.push_back(SS{1, 2});
}
The code can be compiled without any error. However, when the struct is initialized in class, I got compilation error. Can anyone explain it?
struct SS {int a = 0; int s = 2;};
Error:
In function ‘int main()’:
error: no matching function for call to ‘SS::SS(<brace-enclosed initializer list>)’
v.push_back(SS{1, 2});
^
note: candidates are:
note: constexpr SS::SS()
struct SS {int a = 0; int s = 2;};
^
note: candidate expects 0 arguments, 2 provided
note: constexpr SS::SS(const SS&)
note: candidate expects 1 argument, 2 provided
note: constexpr SS::SS(SS&&)
note: candidate expects 1 argument, 2 provided
In C++11, when you use non static data member initialization at the point of declaration like you do here:
struct SS {int a = 0; int s = 2;};
you make the class a non-aggregate. This means you can no longer initialize an instance like this:
SS s{1,2};
To make this initialization syntax work for a non-aggregate, you would have to add a two-parameter constructor:
struct SS
{
SS(int a, int s) : a(a), s(s) {}
int a = 0;
int s = 2;
};
This restriction has been lifted in C++14.
Note that you may want to add a default constructor for the class. The presence of a user-provided constructor inhibits the compiler generated default one.
See related reading here.
Use of a default member initializer renders the class/struct a non-aggregate:
§ 8.5.1 Aggregates
An aggregate is an array or a class (Clause 9) with no user-provided constructors (12.1), no brace-or-equal-initializers for non-static data members (9.2), no private or protected non-static data members (Clause 11), no base classes (Clause 10), and no virtual functions (10.3).
Semantics differ for aggregates and non-aggregates:
Aggregates (e.g., arrays and structs):
Initialize members/elements beginning-to-end.
Non-aggregates:
Invoke a constructor.
v.push_back(SS{1, 2}); // Error, it tries to call SS constructor
Which means you need a constructor now:
struct SS
{
SS(int a, int s) : a(a), s(s)
{
}
int a = 0;
int s = 2;
};
I had the same problem. In my case, I had two structs that both had a few constructors, including copy constructors, inheriting from an abstract parent.
When the advice above didn't help, I finally realized I needed to remove explicit specifier from the copy constructors and that removed the error.
Thought I would share in case another poor soul spends as long finding this mistake as I just did.