From C 11 and above, I can construct a class with list initialization std::vector<int> foo{1,2,3}
or copy list-initialization with std::vector<int> foo = {1,2,3}
. Assuming I have a class as follows
class Bar {
};
class Event{
public:
int time;
Bar* ptr;
Event() = default;
Event(int t, Bar* p):time(t),ptr(p){};
};
What kind of constructor should I define so that I can construct my class instance like this?
Event e1 = {1, nullptr}; // attempt to copy list initialize e1 using curly braces
Event e2{1, nullptr}; // attempt to list initialize e2 using curly braces
Will the compiler generate a list initialize constructor for me if I don't declare it explicitly? I find it really confusing (overwhelm me) to understand the content https://en.cppreference.com/w/cpp/language/list_initialization systematically. I just want to understand some basic principles or find some easy-to-understand references on this topic. Thank you
CodePudding user response:
Seems like you are confusing the idea between List initialization and Aggregate initialization.
While aggregate initialization is a form of list initialization, list initialization often refers to the initialization that uses std::initializer_list
, which is introduced in C 11.
List initialization can often be used to simplify the creation of a member container. To create a constructor that uses std::initializer_list
, you would do:
struct Foo {
std::vector<int> vec;
Foo(std::initializer_list<int> li)
: vec(li)
{}
};
And now you can create a Foo
with: Foo foo{1,2,3,4,5}
or Foo foo = {1,2,3,4,5}
.
std::initializer_list
also has the begin()
and end()
iterator, so you can access the member through for-loops if needed. However, do notice that it does not have a bracket accessor operator[]
, and it must be monotype, which means it is not applicable in your case.
Instead what you are looking for is aggregate initialization. To enable aggregate initialization, all you need is to make sure all members are public visible, and you do not have a user declared constructor:
class Event{
public:
int time;
Bar* ptr;
};
Now you can aggregate initialize a Event
with the syntax you wanted:
Event e1 = {1, nullptr};
Event e2{1, nullptr};
Optionally, you can provide default values for each member:
class Event{
public:
int time = 0;
Bar* ptr = nullptr;
};
int main()
{
Event e1; // e1.time defaulted to 0, e1.ptr defaulted to nullptr
Event e2{5}; // e2.ptr defaulted to nullptr
}
Without the default value, doing Event e1;
could make e1.time
and e1.ptr
be potentially undefined.
CodePudding user response:
You can use varargs:
#include <iostream>
#include <vector>
class Foo {
public:
template <class... T>
Foo(T... a) {
std::cout << "List initialization." << std::endl;
}
};
int main(int, char **) {
Foo foo{1,2,3};
}
Then see this page for more info: https://en.cppreference.com/w/cpp/utility/variadic