I have confusing situation with simple code:
struct Item {
size_t span{};
};
int main() {
Item item{1}; // error is here
return 0;
}
While compiling this I have following error:
test.cpp: In function ‘int main()’:
test.cpp:8:13: error: no matching function for call to ‘Item::Item(<brace-enclosed initializer list>)’
Item i{1};
^
test.cpp:8:13: note: candidates are:
test.cpp:3:8: note: constexpr Item::Item()
struct Item {
^
test.cpp:3:8: note: candidate expects 0 arguments, 1 provided
test.cpp:3:8: note: constexpr Item::Item(const Item&)
test.cpp:3:8: note: no known conversion for argument 1 from ‘int’ to ‘const Item&’
test.cpp:3:8: note: constexpr Item::Item(Item&&)
test.cpp:3:8: note: no known conversion for argument 1 from ‘int’ to ‘Item&&’
Why g++ tries to find a ctor for initializer list in this case instead of simple C-style structure object creating?
If I remove {} from size_t span{} it compiles successfully.
It also happens if I change the line to size_t span = 0 so it seems to be some initialization in declaration issue which exists since c++11.
Usign Item item{1}; means you're doing list-initialisation (of item). List initialisation is defined as follows:
if the type is an aggregate, aggregate initialisation (what you refer to as "C-style struct object creating") happens
...
if the type is a class, constructors are considered
Your class has no constructors. It is also not a (C++11) aggregate, because it contains an initialiser for a non-static data member.
Note that this restriction (member initialisers) was lifted in C++14, so Item is a C++14 aggregate and your code, while not valid C++11, is valid C++14.
Related
Can I define an array of integers as an attribute in a struct in C++?
This is how I tried, output is also posted:
struct SpaceTime{
SpaceTime(int Coordinates[2][2]):
Coordinates_(Coordinates[2][2]){}
public:
int Coordinates_;
};
int main(){
SpaceTime earth({{100,200},{300,400}});
std::cout << earth.Coordinates_[1][1] << std::endl;
}
Output from C++14, Windows 10 Visual Studio:
.\StackOverFlow.cpp: In function 'int main()':
.\StackOverFlow.cpp:28:39: error: no matching function for call to 'SpaceTime::SpaceTime(<brace-enclosed initializer list>)'
SpaceTime earth({{100,200},{300,400}});
^
.\StackOverFlow.cpp:22:5: note: candidate: SpaceTime::SpaceTime(int (*)[2])
SpaceTime(int Coordinates[2][2]):
^~~~~~~~~
.\StackOverFlow.cpp:22:5: note: no known conversion for argument 1 from '<brace-enclosed initializer list>' to 'int (*)[2]'
.\StackOverFlow.cpp:21:8: note: candidate: constexpr SpaceTime::SpaceTime(const SpaceTime&)
struct SpaceTime{
^~~~~~~~~
.\StackOverFlow.cpp:21:8: note: no known conversion for argument 1 from '<brace-enclosed initializer list>' to 'const SpaceTime&'
.\StackOverFlow.cpp:21:8: note: candidate: constexpr SpaceTime::SpaceTime(SpaceTime&&)
.\StackOverFlow.cpp:21:8: note: no known conversion for argument 1 from '<brace-enclosed initializer list>' to 'SpaceTime&&'
.\StackOverFlow.cpp:29:35: error: invalid types 'int[int]' for array subscript
std::cout << earth.Coordinates_[1][1] << std::endl;
Yes, a C++ data member may be an array. However, your example isn't. Your example Coordinates_ is simply a scalar integer. If you had wanted it to be an array, your class definition should instead appear something like this:
class SpaceTime {
public:
int Coordinates_[2][2];
};
Also, if you want this data member to be initialized by a constructor, that construction would need to perform a deep copy of the data.
I alighted on this while permuting with a trivial piece of code:
struct Base0 {};
struct Base1 {};
template<typename... Ts>
struct Derived: Ts... {};
int main() {
Derived<Base0, Base1> d0 {Base0{}, Base1{}}; // OK
Derived<Base0, Base1> d1 (Base0{}, Base1{}); // ERROR
}
I thought both d0 and d1 should have resulted in a compilation error since I can't see how Derived without any matching ctor takes ctor arguments as passed and flags d0's compilation as fine.
There's probably something obvious I'm missing. What is it about the uniform initialisation that's making it pass ? Is it aggregate initialisation or something ? What's happening with the temporaries passed to the ctor ?
Using C++17 online compiler here
Edit
As asked, I'm providing a copy-paste of the spew-out:
main.cpp: In function ‘int main()’:
main.cpp:9:47: error: no matching function for call to ‘Derived::Derived(Base0, Base1)’
Derived<Base0, Base1> d1 (Base0{}, Base1{}); // ERROR
^
main.cpp:5:8: note: candidate: constexpr Derived::Derived()
struct Derived: Ts... {};
^~~~~~~
main.cpp:5:8: note: candidate expects 0 arguments, 2 provided
main.cpp:5:8: note: candidate: constexpr Derived::Derived(const Derived&)
main.cpp:5:8: note: candidate expects 1 argument, 2 provided
main.cpp:5:8: note: candidate: constexpr Derived::Derived(Derived&&)
main.cpp:5:8: note: candidate expects 1 argument, 2 provided
Looks like this is a new C++17 feature of aggregate initialisation:
Each direct public base, (since C++17) array element, or non-static class member, in order of array subscript/appearance in the class definition, is copy-initialized from the corresponding clause of the initializer list.
It comes with the change that a class with bases may now be an aggregate (as long as they are not virtual, private, or protected… though they don't even need to be aggregates! 😲).
Your failing case does not use aggregate initialisation, but instead attempts a good old-fashioned constructor invocation. As you've identified, no such constructor exists.
I have the struct student and I did not declare a constructor. What will happen if I do the following?
struct student{
int assns, mt, finalExam;
float grade(){…}
}
student billy (60, 70, 80);
This answer is written according to the question heading, and not the body, as they seem to be gravely conflicting, hope the OP edits this.
You will encounter a error during compile time.
Code:
#include <iostream>
class test
{
int tt;
};
int main ()
{
test t1 (34);
}
Compiler Error:
In function 'int main()':
10:17: error: no matching function for call to 'test::test(int)' 10:17: note: candidates are:
2:7: note: test::test()
2:7: note: candidate expects 0 arguments, 1 provided
2:7: note: constexpr test::test(const test&)
2:7: note: no known conversion for argument 1 from 'int' to 'const test&'
2:7: note: constexpr test::test(test&&)
2:7: note: no known conversion for argument 1 from 'int' to 'test&&'
This happens as there is no constructor defined which takes a parameter. Without the ctor there is no meaning of class, as you can never initialize its data member, and how can you expect something to be constructed if the construction company itself is absent.
The compiler will throw error.
#include <array>
#include <vector>
#include <cinttypes>
#include <iostream>
using namespace std;
template<size_t N>
struct item_t {
array<uint32_t, N> weight = {0};
};
int main(void) {
vector<item_t<3>> items;
items.emplace_back({{9,2,3}});
cout << items[0].weight[0] << endl;
return 0;
};
I'm at a bit of a loss here. Error is on the emplace_back line and no idea how to resolve it. Any help or hints would be appreciated, thanks.
EDIT
gcc version 4.8.2
$ g++ -std=c++11 test.cpp
test.cpp: In function ‘int main()’:
test.cpp:16:30: error: no matching function for call to ‘std::vector<item_t<3ul> >::emplace_back(<brace-enclosed initializer list>)’
items.emplace_back({{9,2,3}});
^
test.cpp:16:30: note: candidate is:
In file included from /usr/include/c++/4.8/vector:69:0,
from test.cpp:2:
/usr/include/c++/4.8/bits/vector.tcc:91:7: note: void std::vector<_Tp, _Alloc>::emplace_back(_Args&& ...) [with _Args = {}; _Tp = item_t<3ul>; _Alloc = std::allocator<item_t<3ul> >]
vector<_Tp, _Alloc>::
^
/usr/include/c++/4.8/bits/vector.tcc:91:7: note: candidate expects 0 arguments, 1 provided
The problem is with the struct initialization = {0} and with emplace_back.
emplace_back() uses template argument deduction to determine the types of the elements passed to the function. A brace enclosed initializer list is not an expression and doesn't have type and therefore cannot be deduced by the template. You have to explicitly call the constructor here:
items.emplace_back(item_t<3>{{1,2,3}});
There are two issues here :
Trying to init a object of type T like this T{...} is referred to as aggregate initialization. Under some conditions, there is a default behaviour specified for it, even if you don't have a constructor which accepts a initializer_list. In C++11, you are not allowed to provide non-default constructors or in-class initializers. So, given this definition
template<size_t N>
struct item_t {
array<uint32_t, N> weight = {0};
};
you cannot write item_t<3> t{1,2,3};.
That, however, isn't your problem. The reason your code fails is that emplace_back tries to forward the arguments to a constructor of the vectors underlying type. In your case, there isn't a match. Note that nice a braced-init list isn't equivalent to an initializer_list in this context, you cannot solve this problem by adding an initializer_list constructor and will have to help the compiler out some other way.
I'm having trouble initializing a struct that uses in-class initializers:
struct A
{
int a{};
int b{};
};
struct B
{
int a;
int b;
};
int main()
{
A a; // OK
B b{1, 2}; // OK
B b2; // OK, but b.a and b.b are undefined
A a2{1, 2}; // ERROR!
}
Here's the error I'm getting from gcc 4.7.2:
% g++ -std=c++11 test2.cc
test2.cc: In function ‘int main()’:
test2.cc:16:11: error: no matching function for call to ‘A::A(<brace-enclosed initializer list>)’
test2.cc:16:11: note: candidates are:
test2.cc:1:8: note: constexpr A::A()
test2.cc:1:8: note: candidate expects 0 arguments, 2 provided
test2.cc:1:8: note: constexpr A::A(const A&)
test2.cc:1:8: note: candidate expects 1 argument, 2 provided
test2.cc:1:8: note: constexpr A::A(A&&)
test2.cc:1:8: note: candidate expects 1 argument, 2 provided
Should this work according to the standard, or is this actually illegal? Am I abusing the use of in-class initializers? I thought the new syntax would make it so I wouldn't have to write a constructor just to do this initialization, but now it seems that I may have to resort to that old mechanism to avoid the possibility of an uninitialized structure.
You can only use braces if either
the brace content matches a constructor (not your case), or
the class is an aggregate and each brace element matches a class member.
However, a class is an aggregate if (C++11, 8.5.1/1):
it has no brace-or-equal-initializers for non-static members
which your class clearly has. So, you don't have an aggregate, either.
Either write suitable constructors, or remove the brace-or-equal-initializers.