C++ 你如何初始化一个以结构为值的映射?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/4396560/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-28 15:18:16  来源:igfitidea点击:

How do you initialize a map which takes a struct as value?

c++mapstructinitializationassociative-array

提问by augustin

I am using a map as an associative array of IDs -> value, where the value is a struct defining the object:

我将地图用作 ID -> 值的关联数组,其中值是定义对象的结构:

#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"};

}

The above code compiles with g++, but with the following warning:

上面的代码用 g++ 编译,但有以下警告:

warning: extended initializer lists only available with -std=c++0x or -std=gnu++0x

I have read various questions/answers here about struct initialization, but I'm still a bit confused. I have a series of related questions:

我在这里阅读了有关结构初始化的各种问题/答案,但我仍然有点困惑。我有一系列相关问题:

  1. I could add the compiler option -std=c++0x and be done with the warning, but still be none the wiser about the underlying problem. Wouldn't things break if I add a method to the category struct?

  2. What would the best way be to initialize this POD struct (category) in a more C++03 compliant way?

  3. Basically, I am not yet sure of the consequences of doing things one way rather than another way. This kind of associative array (where the key is the ID of an object) is easy with PHP, and I'm still learning about the proper way to do it in C++. Is there anything I should pay attention to in the context of the code above?

  1. 我可以添加编译器选项 -std=c++0x 并完成警告,但仍然不了解潜在问题。如果我向类别结构添加一个方法,事情不会中断吗?

  2. 以更符合 C++03 的方式初始化此 POD 结构(类别)的最佳方法是什么?

  3. 基本上,我还不确定以一种方式而不是另一种方式做事的后果。这种关联数组(其中键是对象的 ID)在 PHP 中很容易,而且我仍在学习在 C++ 中执行此操作的正确方法。在上面的代码上下文中有什么我应该注意的吗?

Edit
The following questions are related, but I didn't understand the answers when I first read them:
C++ initialize anonymous struct
c++ Initializing a struct with an array as a member
Initializing structs in C++

编辑
以下问题是相关的,但我第一次阅读时没有理解答案:
C++ 初始化匿名结构
c++ 使用数组作为成员
初始化结构体在 C++ 中初始化结构体

回答by CB Bailey

In C++ (ISO/IEC 14882:2003), a brace enclosed list of expressions can be used to initialize a variable of aggregatetype in the declaration that defines it.

在 C++ (ISO/IEC 14882:2003) 中,大括号括起来的表达式列表可用于在定义它的声明中初始化聚合类型的变量。

E.g.

例如

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

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

An aggregatetype is an array or a class with no user-declared constructors, no private or protected non-static data members, no base classes, and no virtual functions. Note that a class aggregatedoesn't have to be a POD-class and any array is an aggregatewhether or not the type that it is an array of is an aggregate.

聚合类型是数组或没有用户声明的构造函数,没有私有或保护的非静态数据成员,没有基类,也没有虚拟函数的类。请注意,类聚合不必是 POD 类,并且任何数组都是聚合,无论它是数组的类型是否是聚合。

However, a brace-enclosed list of expressions is only valid as an initializer for an aggregate, it is not generally allowed in other contexts such as assignment or a class constructor's member initialization list.

但是,大括号括起来的表达式列表仅作为聚合的初始化器有效,通常不允许在其他上下文中使用,例如赋值或类构造函数的成员初始化列表。

In the current draft of the next version of C++ (C++0x), a brace enclosed list of expressions (brace-init-list) is allowed in more contexts and when an object is initialized from such an initializer listit is called list-initialization.

在下一版本 C++ (C++0x) 的当前草案中,在更多上下文中允许使用花括号括起来的表达式列表 ( branch-init-list),当从这样的初始化列表初始化对象时,它被称为列表-初始化

New contexts where such a list is allowed include arguments in a function call, function returns, arguments to constructors, member and base initializers and on the right hand side of an assignment.

允许此类列表的新上下文包括函数调用中的参数、函数返回、构造函数的参数、成员和基初始化器以及赋值的右侧。

This means that this is not valid in C++03.

这意味着这在 C++03 中无效。

int main() {
        categories[1] = {1, "First category"};
        categories[2] = {2, "Second category"};
}

Instead you could do something like this.

相反,你可以做这样的事情。

int main() {
        category tmp1 = { 1, "First category" };
        category tmp2 = { 2, "Second category" };

        categories[1] = tmp1;
        categories[2] = tmp2;
}

Alternatively.

或者。

int main() {
        category tmpinit[] = { { 1, "First category" },
                               { 2, "Second category" } };
        categories[1] = tmpinit[0];
        categories[2] = tmpinit[1];
}

Or, you could consider making a factory function for your type. (You could add a constructor for your type but this would make your class a non-aggregate and would prevent you from using aggregate initialization in other places.)

或者,您可以考虑为您的类型创建工厂函数。(您可以为您的类型添加一个构造函数,但这会使您的类成为非聚合类,并会阻止您在其他地方使用聚合初始化。)

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" );
}

回答by Mephane

In the current C++ standard, you can use initializer lists to initialize arrays and structs containing POD values only. The next standard (aka C++0x or C++1x) will allow to do the same on structs containing non-POD types, e.g. std::string. That's what the warning is about.

在当前的 C++ 标准中,您可以使用初始化列表来初始化仅包含 POD 值的数组和结构。下一个标准(又名 C++0x 或 C++1x)将允许对包含非 POD 类型的结构执行相同的操作,例如 std::string。这就是警告的内容。

I'd suggest you add a simple constructor to categorythat takes the id and name and simply call that constructor instead:

我建议你添加一个简单的构造函数,category它接受 id 和 name 并简单地调用该构造函数:

#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");

}

回答by davka

the kind of initialization we are using is introduced only in the emerging C++ standard called C++0x, hence the warning and the compiler option. Some compilers, as g++, already support some of the new features, but the standard itself is not yet accepted. It adds many new features to C++ as we know it. You can read more on Stroustrup's site.

我们正在使用的初始化类型仅在称为 C++0x 的新兴 C++ 标准中引入,因此警告和编译器选项。一些编译器,如 g++,已经支持一些新特性,但标准本身尚未被接受。正如我们所知,它为 C++ 添加了许多新功能。您可以在Stroustrup 的网站上阅读更多内容。

to initialize the structure you can add a ctor (naturally), e.g.

要初始化结构,您可以添加一个ctor(自然),例如

struct category {
        category(int i, const std::string& n): id(i), name(n) {}
        int id;
        std::string name;
};

and then to initialize the map as follows:

然后按如下方式初始化地图:

categories[1] = category(1, "First category");

note that an implicit conversion from const char*to string will work here, or else you can define a ctor with const char*also.

请注意,从const char*到字符串的隐式转换将在这里起作用,否则您也可以定义一个 ctor const char*

回答by AKJ

I know this is old, but one can also use

我知道这是旧的,但也可以使用

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

or:

或者:

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

if one needs more.

如果需要更多。

回答by t.g.

the feature you need is termed aggregatein C/C++. By searching "aggregate c++",you'll find a lot of information detailing the whys and hows.

您需要的功能在 C/C++ 中称为聚合。通过搜索“aggregate c++”,您会找到很多详细说明原因和方法的信息。

1- Wouldn't things break if I add a method to the category struct?

1- 如果我向类别结构添加一个方法,事情会不会中断?

Not necessary unless the method influences the underlying C++ memory layout. For example, a plain function does not matter, but a virtual function will because it's likely laid out before the class members.

除非该方法影响底层 C++ 内存布局,否则不需要。例如,普通函数无关紧要,但虚函数会很重要,因为它可能排在类成员之前。

2- What would the best way be to initialize this POD struct (category) in a more c99 compliant way?

2- 以更符合 c99 的方式初始化此 POD 结构(类别)的最佳方法是什么?

using constructors as the other responders suggest.

使用其他响应者建议的构造函数。

3- Is there anything I should pay attention to in the context of the code above?

3- 在上面的代码上下文中有什么我应该注意的吗?

It may involve redundant copies depending how you design you constructor. but it only matters if you often you need the initialization and you really care about the performance.

它可能涉及冗余副本,具体取决于您如何设计构造函数。但只有当你经常需要初始化并且你真的关心性能时才重要。