C ++,我可以在编译时静态初始化一个std :: map吗?

如果我编码这个

std::map<int, char> example = { (1, 'a'), (2, 'b'), (3, 'c') }; 

然后g ++对我说

 deducing from brace-enclosed initializer list requires #include <initializer_list> in C++98 'example' must be initialized by constructor, not by '{...}' 

这让我很烦恼,因为构造函数是运行时,理论上可能会失败。

当然,如果是这样,它会很快失败,应该一直这样做,所以我应该迅速find并纠正这个问题。

但是,我还是很好奇 – 在编译时是否有初始化map,vector等的地方?


编辑:我应该说,我正在开发embedded式系统。 不是所有的处理器都有一个C ++ 0x编译器。 最stream行的可能会,但我不想遇到困难,必须维护代码的2个版本。

至于Boost,我还没决定。 他们在embedded式系统中使用他们的有限状态机类是很不爽的,所以这就是我在这里编写的Event / State / Fsm类。

叹气,我想我最好放心一点,但是我希望这个讨论对别人有帮助。

不在C ++ 98中。 C ++ 11支持这个,所以如果你启用C ++ 11标志并且包含g ++build议的东西,你可以。

编辑:从海湾合作委员会5 C + + 11默认情况下

这不是完全静态的初始化,但仍然尝试。 如果你的编译器不支持C ++ 0x,我会去std :: map的迭代构造函数

 std::pair<int, std::string> map_data[] = { std::make_pair(1, "a"), std::make_pair(2, "b"), std::make_pair(3, "c") }; std::map<int, std::string> my_map(map_data, map_data + sizeof map_data / sizeof map_data[0]); 

这是非常可读的,不需要任何额外的库,应该在所有编译器中工作。

您可以使用Boost.Assign库:

 #include <boost/assign.hpp> #include <map> int main() { std::map<int, char> example = boost::assign::map_list_of(1, 'a') (2, 'b') (3, 'c'); } 

但是,正如Neil和其他人在下面的评论中指出的那样,这个初始化在运行时发生,类似于UncleBean的提议。

对于C ++ 0x,您可能需要一直使用大括号(对每一对使用新式的语法):

 std::map<int, char> example = { {1,'a'}, {2, 'b'}, {3, 'c'} }; 

那些括号来构造对是没有意义的。 或者,你可以完全命名每一对或使用make_pair(就像你在C ++ 98中做的那样)

 std::map<int, char> example = { std::make_pair(1,'a'), std::make_pair(2, 'b'), std::make_pair(3, 'c') }; 

至于在编译时创build这些实例:不。 STL容器全部封装了运行时内存pipe理。

我想,你只能真正拥有一个像boost这样的元编程库的编译时间映射(如果它是完全正确的,并没有研究它可能有什么好处,那么不是100%确定的):

 using namespace boost::mpl; map< pair<integral_c<int, 1>, integral_c<char, 'a'> >, pair<integral_c<int, 2>, integral_c<char, 'b'> >, pair<integral_c<int, 3>, integral_c<char, 'c'> > > compile_time_map; 

对于C ++ 0x之前的版本,最接近的就是不使用为运行时使用devise的容器(并将自己限制在基本types和聚合)

 struct pair { int first; char second; }; pair arr[] = {{1,'a'}, {2,'b'}}; // assuming arr has static storage 

然后可以使用某种地图视图来访问,或者你可以实现一个包装,它允许类似于Boost.Array所做的聚合初始化。

当然,问题的关键在于实施这个的时间。

如果我的阅读在这里是正确的,那么C ++ 0x initializer-lists 可能会给你像std::mapstd::pair这样的非聚集的静态初始化,但只有在dynamic初始化的时候不会改变语义。
因此, 在我看来 ,如果您的实现可以通过静态分析来validation,如果静态初始化map ,则行为不会发生变化,但是只能得到您所要求的内容,但不能保证map发生。

有一个技巧,你可以使用,但只有当这些数据不会在任何其他静态构造函数中使用。 首先定义一个这样的简单类:

 typedef void (*VoidFunc)(); class Initializer { public: Initializer(const VoidFunc& pF) { pF(); } }; 

然后,像这样使用它:

 std::map<std::string, int> numbers; void __initNumsFunc() { numbers["one"] = 1; numbers["two"] = 2; numbers["three"] = 3; } Initializer __initNums(&__initNumsFunc); 

当然这有点矫枉过正,所以我build议只有在真的需要时才使用它。

在编译时没有标准的方法来初始化std::map 。 正如其他人所提到的,如果可能的话,C ++ 0x将允许编译器优化初始化为静态的,但永远不能保证。

请记住,STL只是一个接口规范。 您可以创build自己的兼容容器并为其提供静态初始化function。

根据您是否计划升级编译器和STL实现(特别是在embedded式平台上),您甚至可以深入研究您正在使用的实现,添加派生类并使用它们!

 template <const int N> struct Map { enum { value = N}; }; template <> struct Map <1> { enum { value = (int)'a'}; }; template <> struct Map <2> { enum { value = (int)'b'}; }; template <> struct Map <3> { enum { value = (int)'c'}; }; std::cout << Map<1>::value ;