Недавно я сталкивался с некоторыми проблемами с списками инициализаторов. Рассмотрим программу, в которой хранятся данные, подобные карте.
struct MyMapLike {
MyMapLike(std::map<std::string, int> data)
:data(std::move(data))
{ }
private:
std::map<std::string, int> data;
};
Это выглядит прямо. Но при инициализации он становится уродливым. Я хочу, чтобы это выглядело как
MyMapLike maps = { { "One", 1 }, { "Two", 2 } };
Но компилятор не хочет принимать это, потому что выше это означает, что он должен искать двухпараметрический конструктор, который может принимать { "One", 1 }
и { "Two", 2 }
соответственно. Мне нужно добавить дополнительные фигурные скобки, чтобы они выглядели как однопараметрический конструктор, принимающий { { ... }, { ... } }
MyMapLike maps = { { { "One", 1 }, { "Two", 2 } } };
Я бы не хотел так писать. Поскольку у меня есть класс, подобный карте, и инициализатор имеет абстрактное значение списка сопоставлений, я хотел бы использовать прежнюю версию и быть независимым от любых таких данных реализации, таких как уровень вложенности конструкторов.
Одна работа заключается в том, чтобы объявить конструктор списка инициализаторов
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;
};
Теперь я могу использовать первое, потому что, когда у меня есть конструктор списка инициализаторов, весь список инициализаторов рассматривается как один элемент, а не разделяется на элементы. Но я думаю, что эта отдельная потребность в конструкторе мертва уродлива.
Я ищу руководство:
- Что вы думаете о первой и последней форме инициализации? Имеет ли смысл иметь в этом случае дополнительные фигурные скобки?
- Считаете ли вы требование добавления конструктора списка инициализаторов в этом случае плохим?
Если вы согласны со мной в том, что прежний способ инициализации лучше, какие решения вы можете придумать?