Как инициализировать частную статическую карту const в С++?

Мне нужен только словарь или ассоциативный массив string = > int.

В этом случае существует тип map С++.

Но мне нужна только одна карта для всех экземпляров (- > статическая), и эта карта не может быть изменена (- > 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();

};

Ответ 1

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

Ответ 2

В стандарте С++ 11 введена унифицированная инициализация, которая делает это намного проще, если ваш компилятор поддерживает его:

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


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

См. также этот раздел от Professional С++ на unordered_maps.

Ответ 3

Если вы нашли 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();

Ответ 4

Я сделал это!:)

Прекрасно работает без С++ 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);

Ответ 5

Если карта должна содержать только записи, которые известны во время компиляции, а ключи к карте - целые числа, то вам вообще не нужно использовать карту.

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

Ответ 6

Другой подход к проблеме:

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
}

Это более эффективно, так как нет копии одного типа из стека в кучу (включая конструктор, деструкторы для всех элементов). Неважно, зависит ли это от вашего использования. Не имеет значения со струнами! (но вы можете или не можете найти эту версию "cleaner" )

Ответ 7

Если вы используете компилятор, который по-прежнему не поддерживает универсальную инициализацию, или у вас есть резервирование при использовании 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;
}();

Ответ 8

Вы можете попробовать следующее:

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

С этой реализацией ваши постоянные статические карты классов являются частным членом и могут быть доступны другим классам с использованием метода public get. В противном случае поскольку он является постоянным и не может быть изменен, вы можете удалить общедоступный метод get и переместите переменную map в открытый раздел классов. Однако я бы оставил метод 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 reset method on
 // this class object. 

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

Я редактировал свой оригинальный пост, не было ничего плохого в исходном коде, в котором я размещал его, скомпилировал, построил и работал правильно, это было просто моя первая версия, которую я представила в качестве ответа, была объявлена ​​как общедоступная, а карта была const, но не была статичной.

Ответ 9

Вызов функции не может появляться в постоянном выражении.

попробуйте следующее: (просто пример)

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

Ответ 10

Я часто использую этот шаблон и рекомендую вам его использовать:

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

Вам не нужно больше не иметь дело с булевой переменной, у вас не будет скрытой глобальной переменной, которая проверяется, если уже был вызван инициализатор статической переменной внутри функции.