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

发布于 2024-08-29 00:39:24 字数 636 浏览 9 评论 0原文

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

对于这种情况,有类型映射 C++。

但我只需要一张地图用于所有实例(-> static),并且该地图无法更改(-> const);

我用 boost 库找到了这种方法,

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

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

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

};

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

There is type map C++ for this case.

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

I have found this way with boost library

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

};

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(11

沫雨熙 2024-09-05 00:39:24

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

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

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

另请参阅 此部分来自 Professional C++,位于 unordered_maps 上。

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

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

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

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

情绪操控生活 2024-09-05 00:39:24
#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() {
}
#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() {
}
难以启齿的温柔 2024-09-05 00:39:24

如果您发现 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';
}

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

a.hpp

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

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 you find boost::assign::map_list_of useful, but can't use it for some reason, you could write your own:

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

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

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();
豆芽 2024-09-05 00:39:24

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

Works fine without 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);
兮子 2024-09-05 00:39:24

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

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

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
    }
}
雨后咖啡店 2024-09-05 00:39:24

解决问题的另一种方法:

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
}

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

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

不奢求什么 2024-09-05 00:39:24

您可以尝试以下操作:

MyClass.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

#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

通过此实现,您的类常量静态映射是私有成员,并且可以使用公共 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.

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

You could try this:

MyClass.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

#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.

 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.

苏璃陌 2024-09-05 00:39:24

如果您使用的编译器仍然不支持通用初始化,或者您对使用 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;
}();

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

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;
}();
你是年少的欢喜 2024-09-05 00:39:24

您可以使用单例模式来实现此目的。

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

然后你可以像这样使用你的地图

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

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
难忘№最初的完美 2024-09-05 00:39:24

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

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

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

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
}
冷夜 2024-09-05 00:39:24

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

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;

当然它的可读性不是很好,但如果没有其他库,我们可以做到最好。
此外,不会有任何冗余操作,例如像您的尝试那样从一张地图复制到另一张地图。

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

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

使用以下内容:

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

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

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文