简体   繁体   English

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

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

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

};

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 的此部分

#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() {
}

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

If you find boost::assign::map_list_of useful, 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();

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
    }
}

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") (但您可能会或可能不会发现此版本“更干净”)

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.通过这个实现,你的类常量静态映射是一个私有成员,其他类可以使用公共 get 方法访问。 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.否则,由于它是常量且无法更改,您可以删除公共 get 方法并将映射变量移动到类公共部分。 I would however leave the createMap method private or protected if inheritance and or polymorphism is required.但是,如果需要继承和/或多态性,我会将 createMap 方法保留为私有或受保护。 Here are some samples of use.以下是一些使用示例。

 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 但不是静态的。

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

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
}

You can use the singleton pattern for this.您可以为此使用单例模式

// The static pointer is initialized exactly once which ensures that 
// there is exactly one copy of the map in the program, it will be 
// initialized prior to the first access, and it will not be destroyed 
// while the program is running.
class myClass {
  private:
  static std::map<int,int> myMap() {
    static const auto* myMap = new std::map<int,int> {
      {1, 2},
      {3, 4},
      {5, 6}
    };
    return *myMap;
  }
}

You can then use your map like this然后你可以像这样使用你的地图

int x = myMap()[i] //where i is a key in the map

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

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

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