Как вы инициализируете карту, которая принимает структуру в качестве значения? - PullRequest
17 голосов
/ 09 декабря 2010

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

#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

Я читал различные вопросы / ответы по поводу инициализации структуры, но я все еще немного сбит с толку.У меня есть ряд связанных вопросов:

  1. Я мог бы добавить опцию компилятора -std = c ++ 0x и покончить с предупреждением, но все же не буду осведомлен об основной проблеме,Не сломается ли ситуация, если я добавлю метод в структуру категории?

  2. Каков наилучший способ инициализации этой структуры (категории) POD более совместимым с C ++ 03 способом?

  3. В сущности, я пока не уверен в последствиях того, что дела идут так или иначе.Этот вид ассоциативного массива (где ключ - это идентификатор объекта) прост с PHP, и я все еще изучаю, как сделать это в C ++.Есть ли что-то, на что я должен обратить внимание в контексте кода выше?

Редактировать
Следующие вопросы связаны, но я не понялответы при первом прочтении:
C ++ инициализирует анонимную структуру
c ++ Инициализация структуры с массивом в качестве члена
Инициализация структур в C ++

Ответы [ 5 ]

20 голосов
/ 10 декабря 2010

В C ++ (ИСО / МЭК 14882: 2003) список выражений в скобках можно использовать для инициализации переменной типа aggregate в объявлении, которое ее определяет.

* 1005 Е.Г. *

struct S { int a; std::string b; };

S x = { 39, "Hello, World\n" };

Тип aggregate - это массив или класс без объявленных пользователем конструкторов, без личных или защищенных нестатических членов-данных, без базовых классов и без виртуальных функций. Обратите внимание, что класс aggregate не обязательно должен быть POD-классом, а любой массив является aggregate независимо от того, является ли тип, из которого он состоит, массивом.

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

В текущем проекте следующей версии C ++ (C ++ 0x) заключенный в скобки список выражений ( brace-init-list ) разрешен в большем количестве контекстов и при инициализации объекта из такого списка инициализаторов он называется list-initialization .

Новые контексты, где такой список разрешен, включают аргументы в вызове функции, возвращаемые функции, аргументы конструкторам, инициализаторам членов и баз и в правой части присваивания.

Это означает, что это недопустимо в C ++ 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];
}

Или вы могли бы рассмотреть возможность создания заводской функции для вашего типа. (Вы можете добавить конструктор для вашего типа, но это сделает ваш класс неагрегированным и не позволит использовать агрегатную инициализацию в других местах.)

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" );
}
10 голосов
/ 09 декабря 2010

В текущем стандарте C ++ вы можете использовать списки инициализаторов для инициализации массивов и структур, содержащих только значения POD. Следующий стандарт (он же C ++ 0x или C ++ 1x) позволит сделать то же самое для структур, содержащих не POD-типы, например, станд :: строка. Вот о чем предупреждение.

Я бы посоветовал вам добавить простой конструктор к 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 голосов
/ 09 декабря 2010

тип инициализации, который мы используем, представлен только в появляющемся стандарте C ++, называемом C ++ 0x, отсюда предупреждение и опция компилятора.Некоторые компиляторы, такие как g ++, уже поддерживают некоторые новые функции, но сам стандарт еще не принят.Он добавляет много новых функций в C ++, как мы его знаем.Вы можете прочитать больше на сайте Страуструпа .

для инициализации структуры вы можете добавить 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*.

2 голосов
/ 03 марта 2019

Я знаю, что это старый, но можно также использовать

std::map<int, std::pair<std::string, int>> categories

или

std::map<int, std::tuple<std::string, int, double>> categories

если нужно больше.

1 голос
/ 09 декабря 2010

нужная вам функция называется агрегат в C / C ++. В поиске «агрегат С ++» вы найдете много информации, подробно описывающей причины и причины.

1- Не сломалось бы, если я добавлю метод к структуре категорий?

Не требуется, если метод не влияет на базовый макет памяти C ++. Например, простая функция не имеет значения, но виртуальная функция будет иметь значение, потому что она, скорее всего, представлена ​​членам класса.

2- Каким будет лучший способ инициализировать эту структуру POD (категорию) более совместимым с99 способом?

с использованием конструкторов, как предлагают другие респонденты.

3- Есть что-нибудь, что я должен заплатить внимание в контексте код выше?

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

...