Problem initializing array of struct{enum;union;} - c++

I have a problem defining s_arr[10] which is supposed to be an array of struct objects, while the struct contains an enum and a union member:
enum E {ENUM_A,ENUM_B};
union U {
String s;
char c[4];
};
struct S {
E e;
U u;
};
S s_arr[10];
I have tried to solve this in different ways, but none of them worked.
Essentially I get the following compilation error:
sketch_mar16a:13:11: error: use of deleted function 'S::S()'
S s_arr[10];
^
/.../sketch_mar16a.ino:8:8: note: 'S::S()' is implicitly deleted because the default definition would be ill-formed:
struct S {
^
sketch_mar16a:8:8: error: use of deleted function 'U::U()'
/.../sketch_mar16a.ino:4:7: note: 'U::U()' is implicitly deleted because the default definition would be ill-formed:
union U {
^
sketch_mar16a:5:10: error: union member 'U::s' with non-trivial 'String::String(const char*)'
String s;
^
sketch_mar16a:8:8: error: use of deleted function 'U::~U()'
struct S {
^
/.../sketch_mar16a/sketch_mar16a.ino:4:7: note: 'U::~U()' is implicitly deleted because the default definition would be ill-formed:
union U {
^
sketch_mar16a:5:10: error: union member 'U::s' with non-trivial 'String::~String()'
String s;
^
sketch_mar16a:13:11: error: use of deleted function 'S::~S()'
S s_arr[10];
^
/.../sketch_mar16a/sketch_mar16a.ino:8:8: note: 'S::~S()' is implicitly deleted because the default definition would be ill-formed:
struct S {
^
sketch_mar16a:8:8: error: use of deleted function 'U::~U()'
/.../sketch_mar16a.ino: In function 'void __static_initialization_and_destruction_0(int, int)':
sketch_mar16a:13:3: error: use of deleted function 'S::~S()'
S s_arr[10];
^
exit status 1
use of deleted function 'S::S()'
Unfortunately, I don't understand where the error message is trying to point me to. I tried to define initializers for the involved classes, but I don't know how (or where) to define an initializer for the union.
Using google, I only found cases where a union contains a struct, but I could not derive the solution for my problem.
Can you explain me, why the "default definition would be ill-formed"? How would the default definition look like and when during compile time does it happen?
NOTE: the code is compiled for an arduino uno using the Arduino IDE

Judging by the following error messages:
sketch_mar16a:8:8: error: use of deleted function 'U::U()'
/.../sketch_mar16a.ino:4:7: note: 'U::U()' is implicitly deleted because the default definition would be ill-formed:
union U {
and
/.../sketch_mar16a/sketch_mar16a.ino:4:7: note: 'U::~U()' is implicitly deleted because the default definition would be ill-formed:
union U {
The presence of String s; in U is the source of the problem. You'll need to define the default constructor and the destructor in U and make sure you do the right thing in those functions.
The following simplified program builds on my machine.
struct String
{
String(char const*) {}
~String() {}
};
enum E {ENUM_A,ENUM_B};
union U {
U() : s(nullptr) {}
~U() {}
String s;
char c[4];
};
struct S {
E e;
U u;
};
int main()
{
S s_arr[10];
}
You'll need proper implementations of U::U() and U::~U() so that your program is well behaved.

Related

Constructor implicitly deleted

The related code is listed below, you could check it on https://godbolt.org/z/3GH8zD.
I could solve the complier compile error indeed.But i am not completely clear about the reason lie behind it.I would be grateful to have some help with this question.
struct A
{
int x;
A(int x = 1): x(x) {} // user-defined default constructor
};
struct F : public A
{
int& ref; // reference member
const int c; // const member
// F::F() is implicitly defined as deleted
};
int main()
{
F f; // compile error
}
Compiler compliains:
Could not execute the program
Compiler returned: 1
Compiler stderr
<source>:10:15: error: declaration does not declare anything [-fpermissive]
10 | const int; // const member
| ^~~
<source>: In function 'int main()':
<source>:16:9: error: use of deleted function 'F::F()'
16 | F f; // compile error
| ^
<source>:7:12: note: 'F::F()' is implicitly deleted because the default definition would be ill-formed:
7 | struct F : public A
| ^
<source>:7:12: error: uninitialized reference member in 'struct F'
<source>:9:14: note: 'int& F::ref' should be initialized
9 | int& ref; // reference member
| ^~~
The right code may be:
struct F
{
int& ref = x; // reference member
const int c = 1; // const member
// F::F() is implicitly defined as deleted
};
The class member int& ref needs to be bound to an int when an object of type F is created.
A compiler-generated default constructor would not know how to bind it, so the compiler merely deletes the default constructor.
In the second snippet you explicitly set the member. (You can do that from C++11).
Have a look at the Deleted implicitly-declared default constructor section in cppreference. It explains under which circumstances the default constructor is deleted:
T has a member of reference type without a default initializer. (since C++11)
T has a const member without user-defined default constructor or a default member initializer (since C++11).
That is, if you don't default initialize your const and reference member variables, the constructor will be deleted and it also explains why your second attempt "worked". In fact, it doesn't work until you make F inherit from A (I guess this was your intention). Otherwise, you can't assign A::x to F::ref.
Note: Even though F::ref=A::x is allowed, there is no point in doing that since F already has access to A::x due to inheritance.
To try to build on #Bathsheba answer.
Let's first understand what a reference is. A reference is essentially a pointer that can't be null this makes them very tricky to initialize.
Let's look at your second class:
struct F : public A
{
int& ref; // reference member
const int c; // const member
// F::F() is implicitly defined as deleted
};
If instead of defining it as int& ref; we define it as int ref; the compiler will say, I have no idea what ref is supoosed to be, so I'll stick some random value into it and be done. And so the default constructor just does ref = /*some num*/;
Let's say it was a pointer instead, i.e int* ref; Once again, the default constructor needs to initialize it to a value, for pointers the most logical value for default initialization is nullptr and so we get int* ref = nullptr;
But what if it is a reference? i.e int& ref;. We can;t initialize the variable to a number, because it is not a number it's a reference "i.e a pointer" to a number. But references can't be null so we can;t use nullptr either. So there is no valid default value initialization for the reference. The only reasonable thing is then to delete the default constructor because there does not exist any default value we can use to initialize one of its members.

C++ Ambiguity of default constructor and something else. What is that something else?

I'm not sure what search terms I even need to use to find the answer to this question, so sorry if this is duplicated. Basically, Why does this compile?
struct A {
A(){};
A(const char*){};
};
int main() {
//const char* b = "what is going on?";
A(b);
return 0;
}
But this does not?
struct A {
A(){};
A(const char*){};
};
int main() {
const char* b = "what is going on?";
A(b);
return 0;
}
test.cpp: In function ‘int main()’:
test.cpp:8: error: conflicting declaration ‘A b’
test.cpp:7: error: ‘b’ has a previous declaration as ‘const char* b’
What feature of c++ is causing this ambiguity?
The main goal of this is to create an anonymous variable on the stack of type A. Similar to A a(b);, but not naming a.
This is caused by an ambiguity in the C++ grammar. A(b); is parsed as a definition of b, an object of type A. This exact issue is described in [stmt.ambig].
To fix this, either use uniform initialization A{b}; or surround it with parentheses to force it to be an expression instead of a declaration (A(b));. Either fix will allow your program to compile.

C++11 POD structure initializing error

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.

Calling class constructor with parameter - request of a member in 'x' which is of non-class type

I have a class A that accepts class B as a constructor parameter. Class B can be constructed from int value. My original code is quite complex, but I hope I've reduced it to the very base case:
class B {
public:
explicit B(int a) : val(a) {}
private:
int val;
};
class A {
public:
A(const B & val) : value(val) {};
void print() {
//does nothing
}
private:
B value;
};
int main() {
int someTimeVar = 22;
A a(B(someTimeVar));
a.print();
}
And this is the error code I'm getting:
$ g++ test.cpp -Wall -O0
test.cpp: In function ‘int main()’:
test.cpp:22:7: error: request for member ‘print’ in ‘a’, which is of non-class type ‘A(B)’
a.print();
^
test.cpp:20:9: warning: unused variable ‘someTimeVar’ [-Wunused-variable]
int someTimeVar = 22;
^
I use GCC (4.9.2 20150304 (prerelease)), platform: arch linux.
The following modification to the main function compiles fine:
int main() {
A a(B(22));
a.print();
}
I'm well aware that using A a(); declares a function, not a object. But I didn't expect that A a(B(some_val)) will do the same, and in my opinion this is what's happening here.
Do you have ideas why this is happening?
Edit: Thank you for all the answers, looks like I need to research more on most vexing parse idea.
BTW it turns out that compiling my code using clang provides more useful error message plus a solution:
$ clang test.cpp
test.cpp:21:8: warning: parentheses were disambiguated as a function declaration [-Wvexing-parse]
A a(B(someTimeVar));
^~~~~~~~~~~~~~~~
test.cpp:21:9: note: add a pair of parentheses to declare a variable
A a(B(someTimeVar));
^
( )
test.cpp:22:6: error: member reference base type 'A (B)' is not a structure or union
a.print();
~^~~~~~
1 warning and 1 error generated.
A a(B(someTimeVar)) is interpreted as A a(B someTimeVar), so a is a function taking parameter of type B and returning A.
This is one of the reasons the uniform initialization was added to C++11:
A a{B{someTimeVar}};
This problem has its own tag here on stackoverflow. most-vexing-parse
Wikipedia har a clear description of the problem and its solution. https://en.wikipedia.org/wiki/Most_vexing_parse.
The line
TimeKeeper time_keeper(Timer());
could be disambiguated either as
a variable definition for variable time_keeper of class TimeKeeper, passed an anonymous instance of class Timer or
a function declaration for a function time_keeper which returns an object of type TimeKeeper and has a single (unnamed) parameter which
is a function returning type Timer (and taking no input). (See
Function object#In C and C++)
Most programmers expect the first, but the C++ standard requires it to
be interpreted as the second.
The solution is to add parenthesis to the argument like:
A a( (B(22)) );
or as others have noted use universal initialization like
A a { B{22} };
A a(B(someTimeVar)); declares a function with the return type A and one argument of type B named someTimeVar. It's the same as A a(B someTimeVar);
It works in A a(B(22)); because 22 is not a valid identifier, so the functio declaration would be invalid.
If your codebase uses C++11 (or newer), you can use uniform initialization with curly braces: A a(B{someTimeVar});

struct initialization with in-class member initializers

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.