简体   繁体   English

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

[英]C++, can I statically initialize a std::map at compile time?

If I code this 如果我编码这个

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

then g++ says to me 然后g ++对我说

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

and that annoys me slightly because the constructor is run-time and can, theoretically fail. 这让我很烦,因为构造函数是运行时的,理论上可能会失败。

Sure, if it does, it will fail quickly and ought to do so consistently, so that I ought to quickly locate & correct the problem. 当然,如果确实如此,它将很快失败并且应该一直这样做,所以我应该快速找到并纠正问题。

But, still, I am curious - is there anyway to initialize map, vector, etc, at compile time? 但是,我仍然很好奇 - 无论如何在编译时初始化地图,矢量等?


Edit: I should have said that I am developing for embedded systems. 编辑:我应该说我正在为嵌入式系统开发。 Not all processors will have a C++0x compiler. 并非所有处理器都具有C ++ 0x编译器。 The most popular probably will, but I don't want to encounter a gotcha & have to maintain 2 versions of the code. 最受欢迎的可能是,但我不想遇到问题并且必须维护2个版本的代码。

As to Boost, I am undecided. 至于Boost,我尚未决定。 They are wishy-washy on the use of their Finite State Machine classes in embedded systems, so that is actually what I am coding here, Event/State/Fsm classes. 他们在嵌入式系统中使用他们的有限状态机类是多么的愚蠢,所以这就是我在这里编写的事件/事件/状态/ Fsm类。

Sigh, I guess I'd better just play it safe, but I hope that this discussion has been helpful for others. 叹了口气,我想我最好安全地玩,但我希望这个讨论对其他人有帮助。

It's not exactly static initialization, but still, give it a try. 它不是完全静态初始化,但仍然试一试。 If your compiler doesn't support C++0x, I'd go for std::map's iteration constructor : 如果您的编译器不支持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]);

This is pretty readable, doesn't require any extra libraries and should work in all compilers. 这非常易读,不需要任何额外的库,应该适用于所有编译器。

Not in C++98. 不是在C ++ 98中。 C++11 supports this, so if you enable C++11 flags and include what g++ suggests, you can. C ++ 11支持这一点,所以如果你启用C ++ 11标志并包含g ++建议的内容,你可以。

Edit: from gcc 5 C++11 is on by default 编辑:从gcc 5 C ++ 11默认开启

You can use Boost.Assign library: 您可以使用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');
}

However, as Neil and others pointed in the comments below, this initialization occurs in runtime, similarly to UncleBean's proposal. 但是,正如Neil和其他人在下面的评论中指出的那样,这种初始化发生在运行时,类似于UncleBean的提议。

With C++0x you might need to use braces all the way (use the new-style syntax for each pair as well): 使用C ++ 0x,您可能需要一直使用大括号(对每对使用新式语法):

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

Those brackets to construct pairs are not meaningful. 构造对的那些括号没有意义。 Alternatively you can fully name out each pair or use make_pair (as you'd do in C++98) 或者,您可以完全命名每对或使用make_pair(就像在C ++ 98中一样)

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

As to creating those instances at compile-time: no. 至于在编译时创建这些实例:没有。 STL containers all encapsulate entirely runtime memory management. STL容器全部封装了运行时内存管理。

I suppose, you'd only really have a compile-time map with libraries like boost's metaprogramming (not 100% sure, if it is entirely correct, and haven't studied what it could be good for): 我想,你真的只有一个编译时的地图,里面有像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;

With pre-C++0x, the closest thing you can get is by not using containers designed for runtime usage (and limiting yourself to fundamental types and aggregates) : 使用前C ++ 0x,您可以获得的最接近的事情是不使用为运行时使用设计的容器(并限制自己使用基本类型和聚合)

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

This could then be accessed using some kind of map view , or you could implement a wrapper that allows for aggregate initialization similar to what Boost.Array does. 然后可以使用某种地图视图访问它,或者您可以实现一个允许聚合初始化类似于Boost.Array的包装器。

Of course the question is wether the benefits justify the time put into implementing this. 当然,问题在于实现这一目标的时间是多么合理。

If my reading is correct here, C++0x initializer-lists may give you static initialization of non-aggregates like std::map and std::pair , but only if that doesn't change semantics compared to dynamic initialization. 如果我的阅读在这里是正确的,C ++ 0x initializer-lists 可能会给你静态初始化非聚合,如std::mapstd::pair ,但前提是这与动态初始化相比不会改变语义。
Thus, it seems to me you can only get what you asked for if your implementation can verify via static analysis that the behaviour doesn't change if the map is statically initialized, but no guarantees that it happens. 因此, 在我看来 ,如果您的实现可以通过静态分析验证如果map是静态初始化的行为不会改变,但是不能保证它发生,那么您只能得到您所要求的内容。

There is a trick you can use, but only if this data will not be used in any other static constructor. 您可以使用一种技巧,但前提是此数据不会在任何其他静态构造函数中使用。 First define a simple class like this: 首先定义一个这样的简单类:

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


Then, use it like this: 然后,像这样使用它:

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


Of course this is a bit overkill so I would recommend using it only if you really have to. 当然这有点矫枉过正,所以我建议只在你真的需要的时候使用它。

There is no standard way to initialize std::map at compile time. 在编译时没有标准的方法来初始化std::map As others have mentioned, C++0x will allow the compiler to optimize the initialization to be static if possible, but that will never be guaranteed. 正如其他人所提到的,如果可能的话,C ++ 0x将允许编译器优化初始化为静态,但这永远不会得到保证。

Remember, though, that the STL is just an interface spec. 但请记住,STL只是一个接口规范。 You can create your own compliant containers and give them static initialization capability. 您可以创建自己的兼容容器并为其提供静态初始化功能。

Depending on whether you plan on upgrading your compiler and STL implementation (particularly on an embedded platform), you might even just dig into the implementation you're using, add derived classes, and use those! 根据您是否计划升级编译器和STL实现(特别是在嵌入式平台上),您甚至可以深入研究您正在使用的实现,添加派生类,并使用它们!

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 ;

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM