Как вы инициализируете карту, которая берет структуру как значение?
Я использую карту как ассоциативный массив идентификаторов → значение, где это значение является структурой, определяющей объект:
#include <map>
struct category {
int id;
std::string name;
};
std::map<int, category> categories;
int main() {
categories[1] = {1, "First category"};
categories[2] = {2, "Second category"};
}
Вышеприведенный код компилируется с помощью g++, но со следующим предупреждением:
warning: extended initializer lists only available with -std=c++0x or -std=gnu++0x
Я прочитал различные вопросы/ответы здесь об инициализации структуры, но я все еще немного смущен. У меня есть ряд связанных вопросов:
-
Я мог бы добавить параметр компилятора -std = С++ 0x и сделать это с предупреждением, но все же не буду более мудрым относительно основной проблемы. Разве не сломаются вещи, если я добавлю метод в структуру структуры?
-
Каким будет лучший способ инициализировать эту структуру (категорию) POD более чем на С++ 03?
-
В принципе, я еще не уверен в последствиях делать что-то в одном направлении, а не в другом. Этот тип ассоциативного массива (где ключ - это идентификатор объекта) легко с PHP, и я все еще узнаю о том, как это сделать на С++. Есть ли что-нибудь, на что я должен обратить внимание в контексте вышеприведенного кода?
Edit
Следующие вопросы связаны, но я не понял ответы, когда их впервые прочитал:
С++ инициализировать анонимную структуру
С++ Инициализация структуры с массивом в качестве участника
Инициализация структур на С++
Ответы
Ответ 1
В С++ (ISO/IEC 14882: 2003) список выражений, заключенных в фигурные скобки, можно использовать для инициализации переменной типа агрегата в объявлении, которое ее определяет.
например.
struct S { int a; std::string b; };
S x = { 39, "Hello, World\n" };
Агрегатный тип - это массив или класс без объявленных пользователем конструкторов, без частных или защищенных нестатических элементов данных, без базовых классов и без виртуальных функций. Обратите внимание, что агрегат класса не должен быть POD-классом, и любой массив является агрегированным независимо от того, является ли он массивом, который является массивом.
Однако список выражений, заключенный в скобки, действителен только как инициализатор для агрегата, он обычно не разрешен в других контекстах, таких как назначение или список инициализации члена конструктора класса.
В текущем черновике следующей версии С++ (С++ 0x) заключенный в скобки список выражений (список команд-скобок) разрешен в большем количестве контекстов, и когда объект инициализируется из такого списка инициализаторов, называется инициализацией списка.
Новые контексты, в которых такой список разрешен, включают в себя аргументы в вызове функции, возврату функции, аргументах для конструкторов, инициализаторах членов и базовых групп и в правой части присваивания.
Это означает, что это недопустимо в С++ 03.
int main() {
categories[1] = {1, "First category"};
categories[2] = {2, "Second category"};
}
Вместо этого вы можете сделать что-то вроде этого.
int main() {
category tmp1 = { 1, "First category" };
category tmp2 = { 2, "Second category" };
categories[1] = tmp1;
categories[2] = tmp2;
}
В качестве альтернативы.
int main() {
category tmpinit[] = { { 1, "First category" },
{ 2, "Second category" } };
categories[1] = tmpinit[0];
categories[2] = tmpinit[1];
}
Или вы могли бы рассмотреть возможность создания функции factory для вашего типа. (Вы можете добавить конструктор для своего типа, но это сделает ваш класс неагрегатным и помешает вам использовать агрегатную инициализацию в других местах.)
category MakeCategory( int n, const char* s )
{
category c = { n, s };
return c;
}
int main()
{
categories[1] = MakeCategory( 1, "First category" );
categories[2] = MakeCategory( 2, "Second category" );
}
Ответ 2
В текущем стандарте С++ вы можете использовать списки инициализаторов для инициализации массивов и структур, содержащих только значения POD. Следующий стандарт (aka С++ 0x или С++ 1x) позволит сделать то же самое на структурах, содержащих не-POD-типы, например. std::string. Это предупреждение.
Я бы предложил добавить простой конструктор в category
, который принимает идентификатор и имя и просто вызывает этот конструктор:
#include <map>
#include <string>
struct category {
category() : id(0), name() {}
category(int newId, std::string newName)
: id(newId), name(newName) {}
int id;
std::string name;
};
std::map<int, category> categories;
int main() {
categories[1] = category(1, "First category");
categories[2] = category(2, "Second category");
}
Ответ 3
тип используемой инициализации вводится только в появляющемся стандарте С++ под названием С++ 0x, поэтому предупреждение и параметр компилятора. Некоторые компиляторы, такие как g++, уже поддерживают некоторые из новых функций, но сам стандарт еще не принят. Он добавляет много новых возможностей на С++, как мы его знаем. Вы можете прочитать больше на сайте Stroustrup.
для инициализации структуры вы можете добавить ctor (естественно), например.
struct category {
category(int i, const std::string& n): id(i), name(n) {}
int id;
std::string name;
};
а затем инициализировать карту следующим образом:
categories[1] = category(1, "First category");
обратите внимание, что здесь будет работать неявное преобразование из const char*
в строку, иначе вы также можете определить ctor с помощью const char*
.
Ответ 4
требуемая функция называется aggregate в C/С++. Выбрав "aggregate С++", вы найдете много информации, детализирующей whys и hows.
1- Не сломаются ли вещи, если я добавлю метод к структуре структуры?
Не требуется, если этот метод не влияет на базовую структуру памяти С++. Например, простая функция не имеет значения, но виртуальная функция будет, потому что она, скорее всего, выложена перед членами класса.
2- Что было бы лучше всего инициализировать эту структуру (категорию) POD более чем c99-совместимым способом?
с использованием конструкторов, как предлагают другие респонденты.
3- Есть ли что-нибудь, что я должен заплатить внимание в контексте код выше?
Он может включать избыточные копии в зависимости от того, как вы проектируете конструктор. но это имеет значение только в том случае, если вам часто требуется инициализация, и вы действительно заботитесь о производительности.