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



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



для этого случая есть тип map C++.



но мне нужна только одна карта для всех экземпляров (- >static) и эта карта не может быть изменена (- >const);



Я нашел этот способ с boost library



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


есть ли другое решение без этого lib?
Я пробовал что-то вроде этого, но всегда есть некоторые проблемы с инициализацией карты.



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

};
856   10  

10 ответов:

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

стандарт 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}
};

см. также этот раздел из профессионального C++, на unordered_maps.

если вы найдете 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';
}

полезно знать, как такие вещи работают, особенно когда они такие короткие, но в этом случае я бы использовал функцию:

а.ГЭС

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

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

отлично работает без 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);

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

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

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

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
}

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

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

вы можете попробовать это:

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 и перемещать карту переменных в секции Public класса. Однако я бы оставил метод 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.

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

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

попробуйте это: (просто пример)

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

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

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

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

Comments

    Ничего не найдено.