Как инициализировать частную статическую карту 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;
}
Вам не нужно больше не иметь дело с булевой переменной, у вас не будет скрытой глобальной переменной, которая проверяется, если уже был вызван инициализатор статической переменной внутри функции.