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

时间:2010-01-31 14:38:27

标签: c++ stl embedded

如果我编码

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 ‘{...}’   

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

当然,如果确实如此,它会很快失败并且应该一直这样做,所以我应该快速定位&amp;纠正问题。

但是,我仍然很好奇 - 无论如何在编译时初始化地图,矢量等?


编辑:我应该说我正在为嵌入式系统开发。并非所有处理器都具有C ++ 0x编译器。最受欢迎的可能会,但我不想遇到一个问题&amp;必须维护2个版本的代码。

至于Boost,我尚未决定。他们在嵌入式系统中使用他们的有限状态机类是多么的愚蠢,所以这就是我在这里编写的事件/事件/状态/ Fsm类。

叹息,我想我最好安全地玩它,但我希望这个讨论对其他人有帮助。

8 个答案:

答案 0 :(得分:37)

这不是完全静态初始化,但仍然试一试。 如果您的编译器不支持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]);

这非常易读,不需要任何额外的库,并且应该适用于所有编译器。

答案 1 :(得分:21)

不在C ++ 98中。 C ++ 11支持这一点,所以如果你启用C ++ 11标志并包含g ++建议的内容,你可以。

编辑:从gcc 5 C ++ 11默认打开

答案 2 :(得分:14)

您可以使用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的提议。

答案 3 :(得分:13)

使用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')
};

至于在编译时创建这些实例:没有。 STL容器全部封装了运行时内存管理。

我想,你真的只有一个编译时的地图,里面有像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;

答案 4 :(得分:4)

使用pre-C ++ 0x,最接近的是不使用为运行时使用而设计的容器(并将自己局限于基本类型和聚合)

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,但仅限于此与动态初始化相比,它不会改变语义 因此,在我看来如果你的实现可以通过静态分析验证如果map被静态初始化,但没有保证,行为不会改变,那么你只能得到你所要求的内容它发生了。

答案 5 :(得分:1)

您可以使用一种技巧,但前提是此数据不会在任何其他静态构造函数中使用。 首先定义一个这样的简单类:

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


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

答案 6 :(得分:1)

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

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

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

答案 7 :(得分:-2)

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 ;
相关问题