web-dev-qa-db-fra.com

Comment initialiser une mappe statique statique privée en C ++?

J'ai juste besoin d'un dictionnaire ou d'un tableau associatif string => int.

Il existe une carte type C++ dans ce cas.

Mais je n'ai besoin que d'une seule carte pour toutes les instances (-> statique) et cette carte ne peut pas être modifiée (-> const);

J'ai trouvé ça avec la librairie boost

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

Existe-t-il une autre solution sans cette librairie? J'ai essayé quelque chose comme ça, mais il y a toujours des problèmes avec l'initialisation de la carte.

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

La norme C++ 11 a introduit l’initialisation uniforme qui simplifie beaucoup cette opération si votre compilateur la prend en charge:

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


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

Voir aussi cette section de Professional C++ , sur unordered_maps.

91
David C. Bishop

Je l'ai fait! :)

Fonctionne bien sans 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

Si tu trouves boost::assign::map_list_of utile, mais ne peut pas l'utiliser pour une raison quelconque, vous pourriez écrivez le vôtre :

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

Il est utile de savoir comment de telles choses fonctionnent, surtout quand elles sont si courtes, mais dans ce cas, j'utiliserais une fonction:

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

Une approche différente du problème:

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
}

Ceci est plus efficace, car il n’existe pas de copie de type unique de pile à tas (constructeur y compris, destructeurs sur tous les éléments). Que cela compte ou non dépend de votre cas d'utilisation. Peu importe avec les ficelles! (mais vous pouvez ou ne pas trouver cette version "plus propre")

6
ypnos

Si la carte ne doit contenir que des entrées connues au moment de la compilation et que les clés de la carte sont des entiers, vous n'avez pas besoin d'utiliser de carte du tout.

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

Si vous utilisez un compilateur qui ne prend toujours pas en charge l'initialisation universelle ou si vous avez des réserves pour utiliser Boost, une autre alternative possible serait la suivante:

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

Vous pouvez essayer ceci:

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

Avec cette implémentation, votre carte static static de classes est un membre privé et peut être accessible à d'autres classes à l'aide d'une méthode get publique. Sinon, comme elle est constante et ne peut pas changer, vous pouvez supprimer la méthode get publique et déplacer la variable map dans la section public classes. Je laisserais toutefois la méthode createMap privée ou protégée si un héritage et/ou un polymorphisme sont requis. Voici quelques exemples d'utilisation.

 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.

J'avais édité mon message original, il n'y avait rien de mal avec le code original dans lequel je postais pour le compiler, le construire et le fonctionner correctement, c'est juste que ma première version que j'ai présentée comme une réponse a été déclarée publique et la carte était const mais n'était pas statique.

1
Francis Cugler

Un appel de fonction ne peut pas apparaître dans une expression constante.

essayez ceci: (juste un exemple)

#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