C ++ में एक निजी स्थिर कास्ट मैप को इनिशियलाइज़ कैसे करें?


108

मुझे केवल शब्दकोश या साहचर्य सरणी string=> की आवश्यकता है int

इस मामले के लिए टाइप मैप C ++ है।

लेकिन मुझे केवल एक मानचित्र forall इंस्टेंस (-> स्टेटिक) की आवश्यकता है और इस मैप को बदला नहीं जा सकता (-> const);

मैं इस तरह से बढ़ावा पुस्तकालय के साथ मिल गया है

 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
आप किन मुद्दों का उल्लेख करते हैं? क्या आप इस मानचित्र को किसी अन्य वैश्विक स्थिर चर / निरंतर से उपयोग करने का प्रयास कर रहे हैं?
Péter Török

यह एक साहचर्य सरणी स्ट्रिंग नहीं है => int, आप एक चार्ट में एक int मैप कर रहे हैं। v = k + 'a' - 1
जॉनसीवेब

जवाबों:


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

3
सादगी के लिए +1, निश्चित रूप से एक Boost.Assignसमान डिजाइन का उपयोग करना बहुत साफ है :)
Matthieu M.

5
+1, धन्यवाद। नोट: मुझे अपनी कार्यान्वयन फ़ाइल में इनिशियलाइज़ेशन लाइन डालनी थी; हेडर फ़ाइल में इसे छोड़ने से मुझे कई परिभाषाओं के कारण त्रुटियां हुईं (जब भी हेडर को कहीं भी शामिल किया गया था तो इनिशियलाइज़ेशन कोड चलेगा)।
System.Cats.Lol 19

1
साथ जी ++ v4.7.3, इस compiles, जब तक मैं जोड़ने cout << A::myMap[1];में main()। यह एक त्रुटि देता है। यदि मैं constक्वालीफायर निकालता हूं , तो त्रुटि नहीं होती है , इसलिए मुझे लगता है कि नक्शे में सी ++ लाइब्रेरी के जी ++ कार्यान्वयन में नहीं, कम से कम, operator[]संभाल नहीं सकता है const map
क्रेग मैकक्यून

2
त्रुटि है:const_map.cpp:22:23: error: passing ‘const std::map<int, int>’ as ‘this’ argument of ‘std::map<_Key, _Tp, _Compare, _Alloc>::mapped_type& std::map<_Key, _Tp, _Compare, _Alloc>::operator[](const key_type&) [with _Key = int; _Tp = int; _Compare = std::less<int>; _Alloc = std::allocator<std::pair<const int, int> >; std::map<_Key, _Tp, _Compare, _Alloc>::mapped_type = int; std::map<_Key, _Tp, _Compare, _Alloc>::key_type = int]’ discards qualifiers [-fpermissive]
क्रेग मैकक्यून

4
वास्तव में, मैप का ऑपरेटर [] एक कास्ट मैप पर काम नहीं कर सकता है क्योंकि यह ऑपरेटर संदर्भित प्रविष्टि बनाता है यदि यह मौजूद नहीं है (क्योंकि यह मैप किए गए मान का संदर्भ देता है)। C ++ 11 ने (KeyValT कुंजी) विधि पेश की है जो आपको किसी दिए गए कुंजी के साथ आइटम का उपयोग करने देता है, अगर वह मौजूद नहीं है, तो एक अपवाद को फेंक दें। ( en.cppreference.com/w/cpp/container/map/at ) यह तरीका कांस्ट इंस्टेंस पर काम करेगा लेकिन एक नॉन-कॉस्ट इंस्टेंस पर तत्व डालने के लिए इस्तेमाल नहीं किया जा सकता (जैसा कि [] ऑपरेटर)।
मबगिल

108

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 पर भी देखें ।


क्या हमें cpp फ़ाइल में समान चिह्न की आवश्यकता है?
फोएद

@ एफोएड: बराबर का चिह्न शानदार है।
जिंक्ड

उपयोग दिखाने के लिए धन्यवाद। यह समझना उपयोगी था कि स्थैतिक चर को कैसे संशोधित किया जाए।
User9102d82

12

मैंने यह किया! :)

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

11

यदि आप 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();

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
}

यह अधिक कुशल है, क्योंकि ढेर से ढेर तक कोई एक प्रकार की प्रतिलिपि नहीं है (सभी तत्वों पर निर्माता, विध्वंसक सहित)। यह मामला आपके उपयोग के मामले पर निर्भर करता है या नहीं। तार के साथ कोई फर्क नहीं पड़ता! (लेकिन आपको यह संस्करण "क्लीनर" मिल सकता है या नहीं)


3
आरवीओ खान और नील के जवाब में नकल को खत्म करता है।

6

यदि मानचित्र में केवल प्रविष्टियाँ हैं जो संकलन समय पर जानी जाती हैं और मानचित्र की कुंजी पूर्णांक हैं, तो आपको मानचित्र का उपयोग करने की आवश्यकता नहीं है।

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

5
+1 यह इंगित करने के लिए कि किसी नक्शे की आवश्यकता नहीं है, हालाँकि, आप इस पर पुनरावृति नहीं कर सकते
विक्टर सेहर

4
यही कारण है कि switch, भयंकर है, हालांकि। क्यों नहीं return key + 'a' - 1?
जॉनसीवेब

12
@Johnsyweb। मुझे लगता है कि मूल पोस्टर द्वारा आपूर्ति की गई मैपिंग केवल एक उदाहरण के रूप में प्रस्तुत की गई थी और वास्तविक मैपिंग का संकेत नहीं है जो उसके पास है। इसलिए, मैं यह भी मानूंगा कि return key + 'a' - 1उसकी वास्तविक मैपिंग के लिए काम नहीं करेगा।
मैथ्यू टी। स्टैबलर

3

आप यह कोशिश कर सकते हैं:

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

इस कार्यान्वयन के साथ आपकी कक्षाएं निरंतर स्थैतिक मानचित्र एक निजी सदस्य हैं और सार्वजनिक प्राप्त विधि का उपयोग करके अन्य वर्गों के लिए सुलभ हो सकता है। अन्यथा चूंकि यह स्थिर है और इसे बदल नहीं सकते हैं, आप सार्वजनिक प्राप्त विधि को हटा सकते हैं और मानचित्र चर को सार्वजनिक अनुभाग में स्थानांतरित कर सकते हैं। हालाँकि, अगर मैं इनहेरिटेंस और पॉलीमॉर्फिज़्म की आवश्यकता है, तो मैं प्राइवेट बनाने की विधि को छोड़ दूंगा या संरक्षित करूंगा। यहाँ उपयोग के कुछ नमूने दिए गए हैं।

 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.

मैंने अपना मूल पोस्ट संपादित किया था, मूल कोड के साथ कुछ भी गलत नहीं था, जिसमें मैंने इसके लिए संकलित, निर्मित और सही तरीके से पोस्ट किया था, यह सिर्फ इतना था कि मेरा पहला संस्करण मैंने एक उत्तर के रूप में प्रस्तुत किया था जिसे मानचित्र सार्वजनिक घोषित किया गया था और नक्शा था कास्ट लेकिन स्थिर नहीं था।


2

यदि आप एक संकलक का उपयोग कर रहे हैं जो अभी भी सार्वभौमिक आरंभ का समर्थन नहीं करता है या बूस्ट का उपयोग करने में आपका आरक्षण है, तो एक और संभावित विकल्प निम्नानुसार होगा

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

0

एक फ़ंक्शन कॉल एक स्थिर अभिव्यक्ति में प्रकट नहीं हो सकता है।

इसे आज़माएँ: (केवल एक उदाहरण)

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

6
एक फ़ंक्शन का उपयोग निश्चित रूप से एक कास्ट ऑब्जेक्ट को इनिशियलाइज़ करने के लिए किया जा सकता है।

ओपी के कोड static map<int,int> myMap = create_map();में गलत है।
प्रसून सौरव

3
प्रश्न में कोड गलत है, हम सभी इस बात से सहमत हैं, लेकिन इसका the निरंतर अभिव्यक्ति ’से कोई लेना-देना नहीं है, जैसा कि आप इस उत्तर में कहते हैं, बल्कि इस तथ्य के साथ कि आप केवल एक वर्ग के स्थिर सदस्यों को ही प्रारंभिक कर सकते हैं घोषणा अगर वे पूर्णांक या enum प्रकार के हैं। अन्य सभी प्रकारों के लिए, प्रारंभ को सदस्य की परिभाषा में किया जाना चाहिए न कि घोषणा में।
डेविड रॉड्रिग्ज - ड्रिबीस

नील का उत्तर जी ++ के साथ संकलित है। फिर भी, मुझे जीएनयू टूलकिन के पुराने संस्करणों में इस दृष्टिकोण के साथ कुछ समस्याएं हैं। क्या कोई सार्वभौमिक सही उत्तर है?
बसिलेव्स

1
@Prasoon: मुझे नहीं पता कि संकलक क्या कहता है, लेकिन प्रश्न कोड में त्रुटि वर्ग घोषणा में वर्ग प्रकार के एक निरंतर सदस्य विशेषता को इनिशियलाइज़ कर रही है, चाहे इनिशियलाइज़ेशन एक स्थिर अभिव्यक्ति है या नहीं। यदि आप एक वर्ग को परिभाषित करते हैं: struct testdata { testdata(int){} }; struct test { static const testdata td = 5; }; testdata test::td;यह संकलित करने में विफल होगा, भले ही प्रारंभिक अभिव्यक्ति के साथ प्रदर्शन किया गया हो ( 5)। अर्थात्, 'स्थिर अभिव्यक्ति' प्रारंभिक कोड की शुद्धता (या इसकी कमी) के लिए अप्रासंगिक है।
डेविड रॉड्रिग्ज़ - dribeas

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

इतना ही नहीं आपको बूलियन वैरिएबल से निपटने के लिए यहां की आवश्यकता नहीं है, आपके पास छिपे हुए वैश्विक वैरिएबल नहीं होंगे जो जांचे जाते हैं कि क्या फंक्शन के अंदर स्टैटिक वैरिएबल को पहले से ही कहा जाता था।


6
वंशानुक्रम अंतिम उपाय का उपकरण होना चाहिए, पहला नहीं।

एक संकलक जो आरवीओ का समर्थन करता है, फ़ंक्शन संस्करणों के साथ निरर्थक नकल को समाप्त करता है। उपलब्ध होने के बाद C ++ 0x चाल शब्दार्थ बाकी को खत्म कर देता है। किसी भी मामले में, मुझे संदेह है कि यह एक अड़चन होने के करीब है।

रोजर, मैं आरवीओ, और& से अच्छी तरह वाकिफ हूं और शब्दार्थ को आगे बढ़ाता हूं। यह अब कम से कम कोड और संस्थाओं के लिए एक समाधान है। साथ ही सभी C ++ 0x विशेषताएं फ़ंक्शन उदाहरण के अंदर स्थिर ऑब्जेक्ट के साथ मदद नहीं करेंगी क्योंकि हमें फ़ंक्शन के अंदर फ़ंक्शन को परिभाषित करने की अनुमति नहीं है।
पावेल चिकुलाव
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.