web-dev-qa-db-ger.com

Wie initialisiere ich eine private statische const map in C ++?

Ich brauche nur ein Wörterbuch oder ein assoziatives Array string => int.

Für diesen Fall gibt es den Typ map C++.

Aber ich brauche nur eine Map für alle Instanzen (-> static) und diese Map kann nicht geändert werden (-> const);

Ich habe diesen Weg mit Boost Library gefunden

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

Gibt es eine andere Lösung ohne diese Bibliothek? Ich habe so etwas versucht, aber es gibt immer einige Probleme mit der Karteninitialisierung.

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

};
93
Meloun
#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() {
}
100
anon

Der C++ 11-Standard führte eine einheitliche Initialisierung ein, die dies viel einfacher macht, wenn Ihr Compiler dies unterstützt:

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


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

Siehe auch dieser Abschnitt aus Professional C++ auf ungeordneten Karten.

91
David C. Bishop

Ich habe es gemacht! :)

Funktioniert gut ohne 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);
12
user2622030

Wenn Sie boost::assign::map_list_of Nützlich finden, es aber aus irgendeinem Grund nicht verwenden können, können Sie schreiben Sie Ihre eigenen :

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

Es ist nützlich zu wissen, wie solche Dinge funktionieren, besonders wenn sie so kurz sind, aber in diesem Fall würde ich eine Funktion verwenden:

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();
11
Roger Pate

Eine andere Herangehensweise an das 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
}

Dies ist effizienter, da es keine einzige Kopie vom Stapel zum Heap gibt (einschließlich Konstruktor, Destruktoren für alle Elemente). Ob dies wichtig ist oder nicht, hängt von Ihrem Anwendungsfall ab. Egal mit Streichern! (aber Sie können oder können nicht diese Version "sauberer" finden)

6
ypnos

Wenn die Map nur Einträge enthalten soll, die zur Kompilierungszeit bekannt sind, und die Schlüssel für die Map Ganzzahlen sind, müssen Sie überhaupt keine Map verwenden.

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

Wenn Sie einen Compiler verwenden, der die universelle Initialisierung immer noch nicht unterstützt, oder wenn Sie Bedenken haben, Boost zu verwenden, ist eine andere mögliche Alternative wie folgt

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

Sie könnten dies versuchen:

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

Mit dieser Implementierung ist die statische Konstantenzuordnung Ihrer Klassen ein privates Mitglied und kann mit einer öffentlichen get-Methode für andere Klassen zugänglich sein. Andernfalls können Sie die public get-Methode entfernen und die Zuordnungsvariable in den public-Abschnitt der Klasse verschieben, da sie konstant ist und nicht geändert werden kann. Ich würde jedoch die createMap-Methode privat oder geschützt lassen, wenn Vererbung und/oder Polymorphismus erforderlich sind. Hier einige Anwendungsbeispiele.

 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.

Ich hatte meinen ursprünglichen Beitrag bearbeitet, es gab nichts Falsches an dem ursprünglichen Code, in dem ich ihn kompiliert, erstellt und ausgeführt habe. Nur meine erste Version, die ich als Antwort präsentierte, war die Karte als öffentlich deklariert und die Karte war const war aber nicht statisch.

1
Francis Cugler

Ein Funktionsaufruf kann nicht in einem konstanten Ausdruck erscheinen.

versuchen Sie dies: (nur ein Beispiel)

#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
}
0
Prasoon Saurav