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

发布于 2024-10-06 15:11:28 字数 1187 浏览 8 评论 0原文

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

#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. 以更符合 C++03 的方式初始化此 POD 结构(类别)的最佳方法是什么?

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

编辑
以下问题是相关的,但当我第一次阅读它们时我不明白答案:
C++ 初始化匿名结构
c++ 使用数组作为成员初始化结构
在 C++ 中初始化结构

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

#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:

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?

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++

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

难得心□动 2024-10-13 15:11:28

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

例如,

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

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

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

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

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

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

这意味着这在 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" );
}

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

E.g.

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

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

An aggregate type 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 aggregate doesn't have to be a POD-class and any array is an aggregate whether or not the type that it is an array of is an aggregate.

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 list it is called list-initialization.

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.

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" );
}
执手闯天涯 2024-10-13 15:11:28

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

我建议您向 category 添加一个简单的构造函数,该构造函数接受 id 和名称,然后简单地调用该构造函数:

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

}

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.

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

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

}
仙女山的月亮 2024-10-13 15:11:28

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

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

or:

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

如果需要更多。

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.

暗恋未遂 2024-10-13 15:11:28

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

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

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* 到 string 的隐式转换将在此处工作,否则您可以定义还有一个带有 const char* 的 ctor。

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.

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

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.

那伤。 2024-10-13 15:11:28

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

1-如果我添加一个,事情不会崩溃吗?
类别结构的方法?

除非该方法影响底层 C++ 内存布局,否则没有必要。例如,普通函数并不重要,但虚函数却很重要,因为它可能位于类成员之前。

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

正如其他响应者建议的那样使用构造函数。

3- 有什么我应该支付的吗
的背景下注意
上面的代码?

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

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

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

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.

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

using constructors as the other responders suggest.

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

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文