This question already has answers here:
Designated initializers in C++20
(2 answers)
Closed 9 months ago.
I am trying to figure out a way to use designated initializers to build a struct, which has been extended off of another one. In my use case, the struct S is a domain object, and the struct S2 adds some application-specific logic for converting it to/from json. As far as I can tell, you cannot use designated initializers if you have a "real" constructor, but all is well if you have a static method returning a new instance for you.
I have a MVP like so (view in Godbolt):
#include <iostream>
struct S {
int i;
};
struct S2 : public S {
static S2 create() {
return S2 { .i = 1234 };
}
};
int main() {
std::cout << S2::create().i;
}
When building (using -std=c++20), I get the following error:
<source>:9:31: error: 'S2' has no non-static data member named 'i'
9 | return S2 { .i = 1234 };
| ^
I expect that the i field would be carried over and initialized, but it isn't.
Am I trying to do something C++ cannot support?
i is data member of S, but not S2.
You can add another braces referring to the base subobject, e.g.
return S2 { {.i = 1234} };
Or you can just take advantage of brace elision:
return S2 { 1234 };
Related
This question already has answers here:
C++11 member initializer list vs in-class initializer?
(3 answers)
Closed 2 years ago.
If I want to assign a default value to an instance variable, which method is to be preferred?
Is there a difference?
Class Foo {
int x = 0;
};
Class Foo {
int x;
Foo() : x(0) {}
};
You may choose to setup an initialization strategy for the member variable both using designated member initializers as well as member initializer list in constructors. If a given constructor does not initialize a given non-static data member, initialization of that data member will fall back on a designated member initializer, if present.
#include <iostream>
template<std::size_t TAG_N> struct Tag{};
struct Foo {
int x{42};
// ^^^^ - designated member initializer (DMI)
Foo() {} // Use DMI -> x is 42
Foo(Tag<0>) {} // Use DMI -> x is 42
Foo(Tag<1>) : x(1) {} // Initialized in mem. init list -> x is 1.
};
int main() {
std::cout << Foo{}.x << " "
<< Foo(Tag<0>{}).x << " "
<< Foo(Tag<1>{}).x << "\n";
// 42 42 1
}
Choosing which approach would enter the domain of opinion-based, but favoring consistency is never a bad advice, and [opinionated] many industry experts recommend using designed member initializers in classes which provide more than one constructor, to avoid the pitfall of e.g. adding a new member to the class but forgetting to initialize it in one the overloaded constructors' member initializer lists.
This question already has answers here:
Benefits of Initialization lists
(5 answers)
Closed 4 years ago.
I have a question regarding difference in initializing an object with and without constructor member initializer list.
In the following code snippet there are two classes Test1 and Test2 each with two constructors, objects of these two classes are created in the default constructor of another class Example.
Object of Test1 is created with one parameter in member initializer list, whereas that of Test2 is created with one parameter inside constructor body of Example.
class Test1 {
public:
Test1() { cout << "Test1 is created with no argument"; }
Test1(int a) { cout << "Test1 is created with 1 argument"; }
};
class Test2 {
public:
Test2() { cout << "Test2 is created with no argument"; }
Test2(int a) { cout << "Test2 is created with 1 argument"; }
};
class Example {
public:
Test1 objTest1;
Test2 objTest2;
Example() : objTest1(Test1(50))
{
objTest2 = Test2(50);
}
};
int main()
{
Example e;
}
The output of the above code is :
Test1 is created with 1 argument
Test2 is created with no argument
Test2 is created with 1 argument
My Questions
Why does object of Test2 is created twice? (The one which is created without member initializer.)
What had happened to the redundant object of Test2? Does it still occupies some memory?
How does member initializer list works in initializing class member variables?
Is there is any performance benefit in using member initializer list? (As Test1 is created only once)
Your Example constructor is (implicitly) equivalent to
Example() : objTest1(Test1(50)), objTest2()
{
objTest2 = Test2(50);
}
That is, the objTest2 object is constructed and initialized once implicitly (this is inserted by the compiler).
Then you inside the body explicitly construct and initialize a temporary Test2 object that is used to assign to objTest2.
Also note that in the initializer list objTest1(Test1(50)) constructs a temporary Test1 object, and passes it to the copy-constructor for the initialization of objTest1 (though most compilers should elide this copying). You can simplify it as plain objTest1(50).
This question already has an answer here:
Why can in-class initializers only use = or {}? [duplicate]
(1 answer)
Closed 5 years ago.
I'm just going through the basic OOP concepts in C++ and came across the following:
class A{
public:
int i(20); //line 1
};
int main()
{
int j(20);
cout<<j<<endl;
A obj;
cout<<obj.i<<endl;
}
I get the following error at line1 when compiling (tried in both gcc and MSVC++),
expected identifier before numeric constant
I know how to assign default value for a non-static member (which can be done from C++11 on wards in different ways), but I couldn't get the reason why only this kind of default value initialization is not possible as doing the same initialization (for normal variables) anywhere else is valid.
What could be the reason for such restriction?
Edited:
From the links and answer provided, it is because "it might read as function declaration in some cases. Because of this ambiguity, it is not allowed."
But consider the following case:
//global scope
struct B{
int j;
};
int B = 10;
int object(B);
This is also a similar case, where int object(B) might be understood as a function object taking B object as argument and with int return type.
I tried this in gcc and MSVC++ and object is treated as an int variable. Why it is not restricted in this case?
Using parentheses was deemed to be too confusing since it would read very similarly to a function declaration. Think about the case of a default constructor:
class A{
public:
int i(); // function declaration -- did you mean to
// use the default constructor instead?
};
There are other ways to do it though:
class A{
public:
int i = 20;
int i{20};
int i = {20};
};
This question already has answers here:
Is returning by rvalue reference more efficient?
(2 answers)
Should I return an rvalue reference parameter by rvalue reference?
(4 answers)
Closed 5 years ago.
I just want to initialize a member data oneObj of class Two as below which compiles fine. I would like to know whether it is advisable to use std::move and && together to initialize an object or just pass the oneObj as a reference to InitObjOne as follows InitObjOne(One & obj) and initialize it. is there any advantage over another. Please clarify.
Note: The InitObjOne need to perform few actions for creating an object of One, I've just given a skeleton of the functionalities here.
#include <iostream>
using namespace std;
class One
{
public:
int x;
};
class Two
{
public:
Two();
private:
One oneObj;
One && InitObjOne();
};
Two::Two() : oneObj(InitObjOne())
{
}
One && Two::InitObjOne()
{
One aObjOne;
return std::move(aObjOne);
}
int main()
{
Two two;
return 0;
}
This question already has answers here:
What is the reason for not being able to deduce array size from initializer-string in member variable?
(3 answers)
Closed 5 years ago.
I'm using struct with initialized value inside a struct, like below example. What I can't understand is why the compiler can't set size of char[] = { .. } in a struct member like it does for a variable declaration? Clang++ gives the following error:
error: array bound cannot be deduced from an in-class initializer
Code:
struct A
{
char s[] = { 'F', 'O', 'O', ... };
};
Structure elements cannot be initialized while they're created, because the structure defines a type and not a variable which can be initialized. You can only initialize a variable of a structure after creating an object of a structure
for example
struct test
{
int var;
};
struct test struct_object = { 7 };
My best guess is it has to do with the passes the compiler is making. In the first pass the structure is initialized, this means it's size MUST be assigned at this time, so if forces the array to size [0]. Then on a later pass when it does assignment it can't store into the size [0] array and it fails to compile. Try giving a size and this should be a good alternative:
#include <iostream>
using namespace std;
struct myStruct{
char myArray[4] = {'1','2','3','\0'};
};
int main()
{
myStruct Mystructure;
cout<<Mystructure.myArray;
return 0;
}
Another solution would be to do it in the base member initialization list for the constructor(which would be required in this case), but I'm not sure how to do that with an array. I would think it would work though as it seems to be a similar reason to why you can't initialize constants if I had to guess.