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.
Related
Is it possible to refer to class members inside "in class initializers"?
Example:
struct Example
{
std::string a = "Hello";
std::string b = a + "World";
};
It seems to work (compiles and runs) but is it ok to do?
This is allowed in default initializers since C++11. Scroll down to the "Usage" section and look at the first example. I copied the explanation and example here for easier reference:
The name of a non-static data member or a non-static member function can only appear in the following three situations:
As a part of class member access expression, in which the class either has this member or is derived from a class that has this member, including the implicit this-> member access expressions that appear when a non-static member name is used in any of the contexts where this is allowed (inside member function bodies, in member initializer lists, in the in-class default member initializers).
struct S
{
int m;
int n;
int x = m; // OK: implicit this-> allowed in default initializers (C++11)
S(int i) : m(i), n(m) // OK: implicit this-> allowed in member initializer lists
{
this->f(); // explicit member access expression
f(); // implicit this-> allowed in member function bodies
}
void f();
};
#include<bits/stdc++.h>
using namespace std;
struct Example
{
string a = "Hello";
string b = a + "World";
};
int main(){
Example val ;
val.a = "Salom";
cout<<val.a<<" "<<val.b;
}
it is okey, you can do it .
but captures the initial result you have If you give a a new value b will not be updated
Consider the following code segment:
#include <iostream>
using std::cout;
using std::endl;
class A
{
public:
//constexpr A (){i = 0;}
constexpr A ():i(0){}
void show (void){cout << i << endl; return;}
private:
int i;
};
class B
{
public:
constexpr B(A a){this->a = a;}
//constexpr B(A a):a(a){}
void show (void){a.show(); return;}
private:
A a;
};
int main (void)
{
A a;
B b(a);
b.show();
return (0);
}
Inside the definition of class A, if the current constructor definition is replaced by the definition commented out:
//constexpr A (){i = 0;}
the following compilation error ensues (note that line numbers correspond to original code):
g++ -ggdb -std=c++17 -Wall -Werror=pedantic -Wextra -c code.cpp
code.cpp: In constructor ‘constexpr A::A()’:
code.cpp:8:30: error: member ‘A::i’ must be initialized by mem-initializer in ‘constexpr’ constructor
constexpr A (){i = 0;}
^
code.cpp:12:13: note: declared here
int i;
^
make: *** [makefile:20: code.o] Error 1
However, the code compiles perfectly with either definition for the constructor of class B (the current as well as the definition commented out in the source code reproduced.)
I have looked at the following pages with the objective of understanding what is going on here:
constexpr specifier (since C++11)
Constant expressions
I must admit that I am not able to figure out why the member initializer list is mandated in the case of the constructor for A, and not in the case of B.
Appreciate your thoughts.
A has a default constructor (which is constexpr by the way). The relevant requirements for a constexpr constructor that you are citing are as follows:
for the constructor of a class or struct, ... every non-variant
non-static data member must be initialized.
The only requirement that it is "initialized". Not "explicitly initialized". A default constructor will meet the initialization requirement. A has a default constructor. So your B's a class member gets initialized by its default constructor, meeting this requirement, so you don't have to explicitly initialize it in B's constructor's initialization list.
On the other hand, your garden variety int does not have a default constructor. For that reason, A's constexpr constructor must initialize it explicitly.
#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};
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.
class A {
public:
A(int v) {
_val = v;
}
private:
int _val;
};
class B {
public:
B(int v) {
a = A(v); // i think this is the key point
}
private:
A a;
};
int main() {
B b(10);
return 0;
}
compiler says:
test.cpp: In constructor ‘B::B(int)’:
test.cpp:15: error: no matching function for call to ‘A::A()’
test.cpp:5: note: candidates are: A::A(int)
test.cpp:3: note: A::A(const A&)
I've learned Java, and I don't know how to deal with this in C++.
Searching for a couple days, plz tell me can C++ do this?
You need to use a Member Initialization List
B(int v):a(v)
{
}
With:
B(int v)
{
a = A(v); // i think this is the key point
}
a is being assigned a value and not being initialized(which is what you intend), Once the body of an constructor begins {, all its members are already constructed.
Why do you get an error?
The compiler constructs a before constructor body { begins, the compiler uses the no argument constructor of A because you didn't tell it otherwiseNote 1, Since the default no argument constructor is not available hence the error.
Why is the default no argument constructor not generated implicitly?
Once you provide any constructor for your class, the implicitly generated no argument constructor is not generated anymore. You provided overloads for constructor of A and hence there is no implicit generation of the no argument constructor.
Note 1
Using Member Initializer List is the way to tell the compiler to use particular overloaded version of the constructor and not the default no argument constructor.
You have to use initialization lists:
class B {
public:
B(int v) : a(v) { // here
}
private:
A a;
};
Otherwise the compiler will try to construct an A using the default constructor. Since you don't provide one, you get an error.
Yes it can, but you haven't provided a default constructor for A(one that takes no parameters or all parameters have default values), so you can only initialize it in the initializer list:
B(int v) : a(v)
{
}
This is because before the constructor body enters, a will be constructed (or attempted to be constructed) with the default constructor (which isn't available).