如何在 C++ 中初始化私有静态常量映射?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2636303/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-28 00:10:39  来源:igfitidea点击:

How to initialize a private static const map in C++?

c++staticmapinitializationconst

提问by Meloun

I need just dictionary or associative array string=> int.

我只需要字典或关联数组string=> int

There is type map C++ for this case.

这种情况下有类型映射 C++。

But I need only one map forall instances(-> static) and this map can't be changed(-> const);

但是对于所有实例我只需要一张地图(-> 静态)并且该地图无法更改(-> const);

I have found this way with boost library

我用boost库找到了这种方式

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

Is there other solution without this lib? I have tried something like this, but there are always some issues with map initialization.

没有这个库还有其他解决方案吗?我尝试过这样的事情,但是地图初始化总是存在一些问题。

class myClass{
private:
    static map<int,int> create_map()
        {
          map<int,int> m;
          m[1] = 2;
          m[3] = 4;
          m[5] = 6;
          return m;
        }
    static map<int,int> myMap =  create_map();

};

采纳答案by Meloun

#include <map>
using namespace std;

struct A{
    static map<int,int> create_map()
        {
          map<int,int> m;
          m[1] = 2;
          m[3] = 4;
          m[5] = 6;
          return m;
        }
    static const map<int,int> myMap;

};

const map<int,int> A:: myMap =  A::create_map();

int main() {
}

回答by David C. Bishop

The C++11 standard introduced uniform initialization which makes this much simpler if your compiler supports it:

C++11 标准引入了统一初始化,如果你的编译器支持它,这会变得更简单:

//myClass.hpp
class myClass {
  private:
    static map<int,int> myMap;
};



//myClass.cpp
map<int,int> myClass::myMap = {
   {1, 2},
   {3, 4},
   {5, 6}
};

See also this section from Professional C++, on unordered_maps.

另请参阅Professional C++中有关 unordered_maps 的此部分

回答by user2622030

I did it! :)

我做到了!:)

Works fine without C++11

没有 C++11 也能正常工作

class MyClass {
    typedef std::map<std::string, int> MyMap;

    struct T {
        const char* Name;
        int Num;

        operator MyMap::value_type() const {
            return std::pair<std::string, int>(Name, Num);
        }
    };

    static const T MapPairs[];
    static const MyMap TheMap;
};

const MyClass::T MyClass::MapPairs[] = {
    { "Jan", 1 }, { "Feb", 2 }, { "Mar", 3 }
};

const MyClass::MyMap MyClass::TheMap(MapPairs, MapPairs + 3);

回答by user2622030

If you find boost::assign::map_list_ofuseful, but can't use it for some reason, you could write your own:

如果您觉得boost::assign::map_list_of有用,但由于某种原因不能使用它,您可以编写自己的

template<class K, class V>
struct map_list_of_type {
  typedef std::map<K, V> Map;
  Map data;
  map_list_of_type(K k, V v) { data[k] = v; }
  map_list_of_type& operator()(K k, V v) { data[k] = v; return *this; }
  operator Map const&() const { return data; }
};
template<class K, class V>
map_list_of_type<K, V> my_map_list_of(K k, V v) {
  return map_list_of_type<K, V>(k, v);
}

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

It's useful to know how such things work, especially when they're so short, but in this case I'd use a function:

了解这些东西的工作原理很有用,尤其是当它们很短时,但在这种情况下,我会使用一个函数:

a.hpp

一个.hpp

struct A {
  static map<int, int> const m;
};

a.cpp

a.cpp

namespace {
map<int,int> create_map() {
  map<int, int> m;
  m[1] = 2; // etc.
  return m;
}
}

map<int, int> const A::m = create_map();

回答by ypnos

A different approach to the problem:

解决问题的不同方法:

struct A {
    static const map<int, string> * singleton_map() {
        static map<int, string>* m = NULL;
        if (!m) {
            m = new map<int, string>;
            m[42] = "42"
            // ... other initializations
        }
        return m;
    }

    // rest of the class
}

This is more efficient, as there is no one-type copy from stack to heap (including constructor, destructors on all elements). Whether this matters or not depends on your use case. Does not matter with strings! (but you may or may not find this version "cleaner")

这更有效,因为没有从堆栈到堆的单一类型复制(包括所有元素的构造函数、析构函数)。这是否重要取决于您的用例。与字符串无关!(但您可能会或可能不会发现此版本“更干净”)

回答by Matthew T. Staebler

If the map is to contain only entries that are known at compile time and the keys to the map are integers, then you do not need to use a map at all.

如果映射只包含编译时已知的条目并且映射的键是整数,那么您根本不需要使用映射。

char get_value(int key)
{
    switch (key)
    {
        case 1:
            return 'a';
        case 2:
            return 'b';
        case 3:
            return 'c';
        default:
            // Do whatever is appropriate when the key is not valid
    }
}

回答by Francis Cugler

You could try this:

你可以试试这个:

MyClass.h

我的类.h

class MyClass {
private:
    static const std::map<key, value> m_myMap; 
    static const std::map<key, value> createMyStaticConstantMap();
public:
    static std::map<key, value> getMyConstantStaticMap( return m_myMap );
}; //MyClass

MyClass.cpp

我的类.cpp

#include "MyClass.h"

const std::map<key, value> MyClass::m_myMap = MyClass::createMyStaticConstantMap();

const std::map<key, value> MyClass::createMyStaticConstantMap() {
    std::map<key, value> mMap;
    mMap.insert( std::make_pair( key1, value1 ) );
    mMap.insert( std::make_pair( key2, value2 ) );
    // ....
    mMap.insert( std::make_pair( lastKey, lastValue ) ); 
    return mMap;
} // createMyStaticConstantMap

With this implementation your classes constant static map is a private member and can be accessible to other classes using a public get method. Otherwise since it is constant and can not change, you can remove the public get method and move the map variable into the classes public section. I would however leave the createMap method private or protected if inheritance and or polymorphism is required. Here are some samples of use.

通过这个实现,你的类常量静态映射是一个私有成员,其他类可以使用公共 get 方法访问。否则,由于它是常量且无法更改,您可以删除公共 get 方法并将映射变量移动到类公共部分。但是,如果需要继承和/或多态性,我会将 createMap 方法保留为私有或受保护。以下是一些使用示例。

 std::map<key,value> m1 = MyClass::getMyMap();
 // then do work on m1 or
 unsigned index = some predetermined value
 MyClass::getMyMap().at( index ); // As long as index is valid this will 
 // retun map.second or map->second value so if in this case key is an
 // unsigned and value is a std::string then you could do
 std::cout << std::string( MyClass::getMyMap().at( some index that exists in map ) ); 
// and it will print out to the console the string locted in the map at this index. 
//You can do this before any class object is instantiated or declared. 

 //If you are using a pointer to your class such as:
 std::shared_ptr<MyClass> || std::unique_ptr<MyClass>
 // Then it would look like this:
 pMyClass->getMyMap().at( index ); // And Will do the same as above
 // Even if you have not yet called the std pointer's reset method on
 // this class object. 

 // This will only work on static methods only, and all data in static methods must be available first.

I had edited my original post, there was nothing wrong with the original code in which I posted for it compiled, built and ran correctly, it was just that my first version I presented as an answer the map was declared as public and the map was const but wasn't static.

我编辑了我的原始帖子,我发布的原始代码没有任何问题,我为它编译、构建和运行正确,只是我作为答案提出的第一个版本地图被声明为公开,地图是const 但不是静态的。

回答by Abhijit

If you are using a compiler which still doesn't support universal initialization or you have reservation in using Boost, another possible alternative would be as follows

如果您使用的编译器仍然不支持通用初始化,或者您对使用 Boost 有所保留,另一种可能的选择如下

std::map<int, int> m = [] () {
    std::pair<int,int> _m[] = {
        std::make_pair(1 , sizeof(2)),
        std::make_pair(3 , sizeof(4)),
        std::make_pair(5 , sizeof(6))};
    std::map<int, int> m;
    for (auto data: _m)
    {
        m[data.first] = data.second;
    }
    return m;
}();

回答by Prasoon Saurav

A function call cannot appear in a constant expression.

函数调用不能出现在常量表达式中。

try this: (just an example)

试试这个:(只是一个例子)

#include <map>
#include <iostream>

using std::map;
using std::cout;

class myClass{
 public:
 static map<int,int> create_map()
    {
      map<int,int> m;
      m[1] = 2;
      m[3] = 4;
      m[5] = 6;
      return m;
    }
 const static map<int,int> myMap;

};
const map<int,int>myClass::myMap =  create_map();

int main(){

   map<int,int> t=myClass::create_map();
   std::cout<<t[1]; //prints 2
}

回答by Pavel Chikulaev

I often use this pattern and recommend you to use it as well:

我经常使用这种模式,并建议您也使用它:

class MyMap : public std::map<int, int>
{
public:
    MyMap()
    {
        //either
        insert(make_pair(1, 2));
        insert(make_pair(3, 4));
        insert(make_pair(5, 6));
        //or
        (*this)[1] = 2;
        (*this)[3] = 4;
        (*this)[5] = 6;
    }
} const static my_map;

Sure it is not very readable, but without other libs it is best we can do. Also there won't be any redundant operations like copying from one map to another like in your attempt.

当然,它的可读性不是很强,但如果没有其他库,我们最好能做到。也不会有任何多余的操作,例如在您的尝试中从一张地图复制到另一张地图。

This is even more useful inside of functions: Instead of:

这在函数内部更有用:而不是:

void foo()
{
   static bool initComplete = false;
   static Map map;
   if (!initComplete)
   {
      initComplete = true;
      map= ...;
   }
}

Use the following:

使用以下内容:

void bar()
{
    struct MyMap : Map
    {
      MyMap()
      {
         ...
      }
    } static mymap;
}

Not only you don't need here to deal with boolean variable anymore, you won't have hidden global variable that is checked if initializer of static variable inside function was already called.

您不仅不再需要在这里处理布尔变量,而且如果已经调用了函数内部静态变量的初始化程序,您将不会检查隐藏的全局变量。