Подтвердить что ты не робот

Как вы инициализируете карту, которая берет структуру как значение?

Я использую карту как ассоциативный массив идентификаторов → значение, где это значение является структурой, определяющей объект:

#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
Следующие вопросы связаны, но я не понял ответы, когда их впервые прочитал:
С++ инициализировать анонимную структуру
С++ Инициализация структуры с массивом в качестве участника
Инициализация структур на С++

4b9b3361

Ответ 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- Есть ли что-нибудь, что я должен заплатить внимание в контексте код выше?

Он может включать избыточные копии в зависимости от того, как вы проектируете конструктор. но это имеет значение только в том случае, если вам часто требуется инициализация, и вы действительно заботитесь о производительности.