Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Initializing from an initializer list, but without {{{{{{{{ ... }}}}}}}}?

Tags:

I recently stumbles across some problem with initializer lists. Consider a program that stores map-like data

struct MyMapLike {   MyMapLike(std::map<std::string, int> data)     :data(std::move(data))   { }  private:   std::map<std::string, int> data; }; 

That looks straight forward. But when initializing it, it becomes ugly. I want to let it look like

MyMapLike maps = { { "One", 1 }, { "Two", 2 } }; 

But the compiler doesn't want to accept this, because the above means that it should look for a two-parameter constructor that can accept { "One", 1 } and { "Two", 2 } respectively. I need to add extra braces, to make it look like a single-parameter constructor accepting the { { ... }, { ... } }

MyMapLike maps = { { { "One", 1 }, { "Two", 2 } } }; 

I would not like to write it like that. Since I have a map-like class, and the initializer has the abstract value of a mapping-list, I would like to use the former version, and be independent of any such implementation details like level of nesting of constructors.

One work around is to declare an initializer-list constructor

struct MyMapLike {   MyMapLike(std::initializer_list<      std::map<std::string, int>::value_type     > vals)     :data(vals.begin(), vals.end())   { }    MyMapLike(std::map<std::string, int> data)     :data(std::move(data))   { }  private:   std::map<std::string, int> data; }; 

Now I can use the former, because when I have an initializer-list constructor, the whole initializer list is treated as one element instead of being splitted into elements. But I think this separate need of the constructor is dead ugly.

I'm looking for guidance:

  • What do you think about the former and latter form of initialization? Does it make sense to be required to have extra braces in this case?
  • Do you consider the requirement for addition of an initializer list constructor in this case bad?

If you agree with me on that the former way of initialization is nicer, what solutions can you think of?

like image 568
Johannes Schaub - litb Avatar asked Apr 20 '11 16:04

Johannes Schaub - litb


People also ask

Does initializer list run before constructor?

The initializer list is used to directly initialize data members of a class. An initializer list starts after the constructor name and its parameters.

Can you initialize a vector with initializer list?

Initializer lists are not limited to just normal Vectors, and can be used to initialize multi-dimensional vectors as well. All you have to do is nest initializer lists within each other as shown below.

What is the advantage of initializer list in C++?

The most common benefit of doing this is improved performance. If the expression whatever is the same type as member variable x_, the result of the whatever expression is constructed directly inside x_ — the compiler does not make a separate copy of the object.

When must you use a member initializer list?

Initializer List is used in initializing the data members of a class. The list of members to be initialized is indicated with constructor as a comma-separated list followed by a colon. Following is an example that uses the initializer list to initialize x and y of Point class.


2 Answers

Since I have a map-like class, and the initializer has the abstract value of a mapping-list, I would like to use the former version

And herin lies the problem: it's up to you to supply the constructors that allow your class to be treated like a map. You called your solution a work-around, but there's nothing to work around. :)

But I think this separate need of the constructor is dead ugly.

It is, but unfortunately since it's your class, you have to specify how the initializer lists work.

like image 131
GManNickG Avatar answered Sep 20 '22 22:09

GManNickG


What do you think about the former and latter form of initialization? Does it make sense to be required to have extra braces in this case?

I think so. I think it would permit too much ambiguity to allow a constructor be called not just when the syntax matches that constructor, but when the syntax matches some constructor of the single argument to the constructor, and so on recursively.

struct A { int i; }; struct B { B(A) {}  B(int) {} }; struct C { C(B) {} };  C c{1}; 

Do you consider the requirement for addition of an initializer list constructor in this case bad?

No. It lets you get the syntax you want but without creating the problems that arise if we make the compiler search harder for a constructor to use.

like image 31
bames53 Avatar answered Sep 19 '22 22:09

bames53