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