我使用地图作为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
我已经阅读了有关结构初始化的各种问题/答案,但我仍然有点困惑。我有一系列相关问题:
我可以添加编译器选项-std = c ++ 0x并完成警告,但仍然没有关于底层问题的明智之处。如果我在类别struct中添加一个方法会不会破坏?
以更符合C ++ 03的方式初始化此POD结构(类别)的最佳方法是什么?
基本上,我还不确定以某种方式而非另一种方式做事的后果。这种关联数组(其中键是对象的ID)很容易用PHP,我仍然在学习在C ++中使用它的正确方法。在上面的代码中是否有任何我应该注意的事项?
修改
以下问题是相关的,但是当我第一次阅读时我不明白答案:
C++ initialize anonymous struct
c++ Initializing a struct with an array as a member
Initializing structs in C++
答案 0 :(得分:20)
在C ++(ISO / IEC 14882:2003)中,括号括起的表达式列表可用于在定义它的声明中初始化 aggregate 类型的变量。
E.g。
struct S { int a; std::string b; };
S x = { 39, "Hello, World\n" };
聚合类型是一个数组或类,没有用户声明的构造函数,没有私有或受保护的非静态数据成员,没有基类,也没有虚函数。请注意,类聚合不必是POD类,任何数组都是聚合,无论它是数组的类型是聚合。
但是,括号括起的表达式列表仅作为聚合的初始值设定项有效,通常不允许在其他上下文中使用,例如赋值或类构造函数的成员初始化列表。
在下一版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" );
}
答案 1 :(得分:10)
在当前的C ++标准中,您可以使用初始化列表来初始化仅包含POD值的数组和结构。下一个标准(又名C ++ 0x或C ++ 1x)将允许在包含非POD类型的结构上执行相同的操作,例如:的std :: string。这就是警告的内容。
我建议你为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");
}
答案 2 :(得分:3)
我们正在使用的初始化类型仅在新兴的C ++标准C ++ 0x中引入,因此是警告和编译器选项。一些编译器,如g ++,已经支持一些新功能,但标准本身尚未被接受。它为我们所知道的C ++增加了许多新功能。您可以在Stroustrup's site上阅读更多内容。
初始化您可以添加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*
到字符串的隐式转换可以在此处使用,否则您也可以使用const char*
定义ctor。
答案 3 :(得分:1)
您需要的功能在C / C ++中称为聚合。通过搜索“聚合c ++”,你会发现很多信息,详细说明了这些原因和方法。
1-如果我添加一个,不会破坏 类别struct的方法?
除非该方法影响底层C ++内存布局,否则没有必要。例如,普通函数无关紧要,但虚函数会因为它可能在类成员之前布局。
2-最好的方式是什么 初始化此POD结构(类别) 以更符合c99的方式?
使用构造函数作为其他响应者的建议。
3-我应该支付任何费用 注意在上下文中 上面的代码?
根据您设计构造函数的方式,它可能涉及冗余副本。但只有你经常需要初始化并且你真的关心性能才会很重要。
答案 4 :(得分:1)
我知道这很旧,但是也可以使用
std::map<int, std::pair<std::string, int>> categories
或:
std::map<int, std::tuple<std::string, int, double>> categories
如果需要更多。