Compiler offers private constructor as a candidate in program code - c++

#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};

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.

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

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.

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.

C++ Template constructor of a inherited class

From what I understand about inheritance in C++ is that whenever the constructor of a child class is called, constructor of the parent class is called automatically. And as for templated constructors, data type of the template argument is infered automatically i.e. we don't need to specify template arguments separately. The program generates a compilation error which I don't seem to understand.
#include <iostream>
#include <list>
#include <algorithm>
using namespace std;
class A{
public:
int x;
int y;
int first(){
return x;
}
int second(){
return y;
}
};
class C{
public:
float a,b;
C(){
a = 0.0f;
b = 0.0f;
}
template<class T>
C(T t){
a = t.first();
b = t.second();
}
};
class D: public C{
public:
float area(){
return a*b;
}
}
int main(){
A a;
a.x = 6;
a.y = 8;
C c(a);
D d(a);
cout<<c.a<<" "<<c.b<<" "<<d.area()<<endl;
}
Compilation error generated
test.cpp: In function ‘int main()’:
test.cpp:56:8: error: no matching function for call to ‘D::D(A&)’
test.cpp:56:8: note: candidates are:
test.cpp:44:7: note: D::D()
test.cpp:44:7: note: candidate expects 0 arguments, 1 provided
test.cpp:44:7: note: D::D(const D&)
test.cpp:44:7: note: no known conversion for argument 1 from ‘A’ to ‘const D&’
I have no idea what is happening here. Any ideas?
D has to pass the constructor argument to C, since you are not using default constructors.
class D : public C {
public:
template <typename T> D (T t) : C(t) {}
float area () { /* ... */ }
};
The reason for the error is that you are trying to construct D with a parameter, but have not declared any constructor that would allow you to do so. Furthermore, you have to pass the parameter into C, otherwise the compiler will use C's default constructor.
The compiler error message can be analyzed like this.
test.cpp:56:8: error: no matching function for call to ‘D::D(A&)’
The compiler is complaining about:
D d(a);
And that it can't figure out how to construct a D when passed something of type A.
It then presents the two choices of constructors it knows about:
test.cpp:44:7: note: D::D()
test.cpp:44:7: note: D::D(const D&)
And it points out that for each one, there is a reason it can't use it. For the first one, it doesn't take any arguments. For the second one, it has no way to convert something of type A into type D.
From what I understand about inheritance in C++ is that whenever the constructor of a child class is called, constructor of the parent class is called automatically.
Careful: The constructor of the parent class is automatically called with the same arguments as the constructor of the child class.
As for the specific problem at hand: There is no constructor declared for class D. You'll get a default constructor and copy constructor as freebies, but not that template-based constructor in class C. Constructors aren't inherited.