2017-05-09 8 views
5

मेरे पास एक स्थिति है, जहां मैं एक नक्शा रखना चाहता हूं जो प्रारंभ करने के बाद कुंजी जोड़ने/हटाने की अनुमति नहीं देता है, लेकिन मानों को बदलने की अनुमति है (इस प्रकार मैं केवल नक्शा const नहीं कर सकता)। यानीकॉन्स कुंजी के साथ मानचित्र लेकिन गैर कॉन्स वैल्यू?

/*semi-const*/ map<int,int> myMap = initMap(); 

myMap[1] = 2;     // NOT OK, because potentially adds a new key 
myMap.at(1) = 2;    // OK, because works only if key is present 
for (auto & element : myMap) { 
    element.second = 0;  // OK, values may change 
} 

मैं std::map के लिए अपने खुद के आवरण लिख सकता है, लेकिन मैं महसूस कर रही यह कुछ भी असामान्य नहीं है कि है, तो मुझे आश्चर्य है कि अगर वहाँ पहले से मौजूदा समाधान है।

क्या मानचित्र के लिए कुछ मानक मुहावरे है जो कुंजी जोड़ने/हटाने की अनुमति नहीं देता है, जबकि मान बदल सकते हैं?

पुनश्च: मुझे पता है कि अकेले शीर्षक, थोड़ा अस्पष्ट है, क्योंकि कुंजी पहले से ही एक नक्शे में const रहे हैं, लेकिन मुझे आशा है कि यह स्पष्ट है कि मैं क्या मतलब है ...

+0

नहीं, मुझे लगता नहीं मिलते हैं, कुछ भी अर्थ की दृष्टि से आपकी आवश्यकता के बराबर ('const' और' mutable' के साथ) आप 'के std :: map' बाहर मजबूर करने के लिए की संभावना नहीं है अच्छी तरह से पढ़ें, 'std :: map' को इस –

+0

जैसे उपयोग करने के लिए डिज़ाइन नहीं किया गया है, इस तरह का मानचित्र अपशिष्ट होगा। आप क्रमबद्ध 'std :: vector' या इसी तरह का उपयोग करके अपनी खुद की कक्षा बना सकते हैं। मानचित्र का उपयोग करने के लिए एक निश्चित कीमत है, लाभ के बिना उस कीमत का भुगतान (पुनर्विक्रय करने की क्षमता आदि) अनुचित लगता है। – Slava

उत्तर

0

मैं 2 विकल्प यहाँ

देखना
  1. नक्शा स्थिरांक करें और जब कुछ

    स्थिरांक std :: नक्शा myMap बदलते const_cast का उपयोग करें;

    myMap [1] = 2; // ठीक नहीं है, क्योंकि कॉन्स मैप

    (const_cast &> (myMap))। (1) = 2; // const_cast साथ ठीक

  2. एक आवरण वर्ग बना सकते हैं या एक कस्टम मानचित्र केवल है पढ़ सकते हैं और अद्यतन मौजूदा मूल्य तरीकों

मुझे नहीं लगता कि यह है कि एक नक्शा बनाने के लिए रास्ते में एक का निर्माण किया है निकाले जाते हैं केवल अद्यतन मान के साथ, और प्रतिबंधित और सम्मिलित करें।

+0

क्षमा करें, लेकिन यह वास्तव में मदद नहीं करता है। 'Const_cast' का उपयोग एक नई कुंजी जोड़ने के लिए भी किया जा सकता है, इसलिए जब भी मैं मानचित्र को स्पर्श करता हूं तो मुझे सावधान रहना होगा, जो कि मैं – user463035818

4

क्या आप एक रैपर बना सकते हैं जिसमें वह मान शामिल है जो मान को const पर परिवर्तित करने की अनुमति देता है और उसे map में डाल देता है? कुछ की तरह:

template<typename T> 
class Mutable { 
    mutable T value; 
public: 
    const Mutable& operator=(const T& v) const { value = v; return *this; } 
    T& get() const { return value; } 
}; 

फिर अपने मैप प्रकार

const std::map<int, Mutable<int>> 

Live demo का हो सकता है।

+0

से बचने के लिए बिल्कुल वही हूं, मैं इसे – user463035818

+0

का प्रयास करूंगा यदि मूल्य प्रतिलिपि द्वारा वापस किया जाता है, उत्परिवर्तन की बात क्या है? इसके अलावा, महान सामान्य दिशा। +1 – StoryTeller

+0

इस तथ्य का एक निश्चित संकेत है कि मैं म्यूटेबल फ़ील्ड का उपयोग नहीं करता हूं, तथ्य यह है कि मैं संकलन के लिए 'ऑपरेटर =' के लिए अपनी आवश्यकता को याद करता हूं। – StoryTeller

1

मानक लाइब्रेरी से कंटेनर एक ऐसे उपयोग के लिए अनुकूलित कक्षाएं हैं जिन्हें के रूप में उपयोग किया जा सकता है या उच्च स्तर के वर्गों में शामिल किया जाता है।

यहां आपकी आवश्यकता (आरंभ करने के बाद तय की गई कुंजी) स्टैंडएट लाइब्रेरी कंटेनर द्वारा कवर नहीं है, इसलिए आपको अपना स्वयं का कार्यान्वयन करना होगा। यह नहीं एक std::map हो जाएगा के रूप में, तुम सिर्फ आपरेशन की जरूरत है, शायद ज्यादा कुछ नहीं है कि operator [] ...

+3

"सी ++ जावा नहीं है" यह यहां कैसे प्रासंगिक है? मैंने 10 से अधिक वर्षों से कोई जावा नहीं लिखा, इसलिए मेरी अपेक्षाएं वहां से नहीं आ रही हैं। हालांकि, अब तुमने मेरी जिज्ञासा उठाई। आप जावा में ऐसा कैसे करेंगे? – user463035818

+0

मुख्य अंतर यह है कि मानक जावा कंटेनर इंटरफेस के कार्यान्वयन होते हैं, और मानक पुस्तकालय में भी मददगार शामिल होते हैं ताकि आप आसानी से कस्टम कार्यान्वयन कर सकें। इसका मतलब है कि आपके कार्यान्वयन वास्तव में 'सूची' या 'मानचित्र' हैं, जब सी ++ में कोई कंटेनर इंटरफ़ेस मानक लाइब्रेरी में मौजूद नहीं है, और कंटेनर का अर्थ आगे व्युत्पन्न नहीं किया जाता है। –

+0

लेकिन सी ++ कंटेनर टेम्पलेट्स हैं जो आमतौर पर इंटरफ़ेस आधारित डिज़ाइन की तुलना में अधिक लचीलापन की अनुमति देते हैं, इसलिए मुझे आपका पॉइंट नहीं मिलता है। – user463035818

1

मैं आमतौर पर सी में एक ख़तरा ++ एक सुविधा की तुलना में अधिक के रूप में इस संबंध में अगर यह फिट बैठता है लागू कर सकते हैं, लेकिन, आपका आवेदन, आप केवल सूचक मूल्यों का उपयोग कर सकते हैं।

#include <map> 
#include <memory> 

int main(int argc, char ** argv) 
{ 
    using namespace std; 
    const map<int, shared_ptr<int>> myMap = { {1, make_shared<int>(100)} }; 
    // *(myMap[1]) = 2; // Does not compile 
    *(myMap.at(1)) = 2; 
    for (auto & element : myMap) 
    { 
     *(element.second) = 0; 
    } 
    return 0; 
} 

वास्तव में सिर्फ this other answer का एक सरल संस्करण है कौन सा (जाहिर है आप shared_ptr/unique_ptr के बीच के रूप में की जरूरत है चुन सकते हैं)।

1

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

अनिवार्य रूप से, डिफ़ॉल्ट निर्माण को अक्षम करके आप std::map द्वारा प्रदान किए गए इंडेक्स एक्सेस ऑपरेटर को आमंत्रित करने की क्षमता को हटा देते हैं। अन्य विधियां उपलब्ध रहेंगी क्योंकि std::map एक क्लास टेम्पलेट है और सदस्य फ़ंक्शंस का मूल्यांकन तब तक नहीं किया जाएगा जब तक उन्हें बुलाया नहीं जाता है। इसलिए, std::map::at ठीक काम करेगा लेकिन std::map::operator[] परिणामस्वरूप एक संकलन-समय त्रुटि होगी।

क्रिस द्वारा प्रेरित आप डिफ़ॉल्ट निर्माण को अक्षम करने के लिए मैप किए गए प्रकार पर एक रैपर का उपयोग कर सकते हैं। मैंने अपना डेमो लिया और इसे डिफॉल्ट निर्माण को अक्षम करने का तरीका दिखाने के लिए थोड़ा सा tweaked और const std::map के बजाय std::map के साथ इसका इस्तेमाल किया।

template<typename T> 
class RemoveDefaultConstruction { 
    T value; 
public: 
    RemoveDefaultConstruction() = delete; // The magic is here 
    RemoveDefaultConstruction(const RemoveDefaultConstruction &other) noexcept(std::is_nothrow_copy_constructible<T>::value) = default; 
    RemoveDefaultConstruction(RemoveDefaultConstruction &&other) noexcept(std::is_nothrow_move_constructible<T>::value) = default; 
    RemoveDefaultConstruction(T &&t) noexcept(std::is_nothrow_constructible<T, decltype(std::forward<T>(t))>::value) : 
    value{std::forward<T>(t)} { 
    } 

    RemoveDefaultConstruction& operator=(const RemoveDefaultConstruction &other) = default; 
    RemoveDefaultConstruction& operator=(RemoveDefaultConstruction &&other) = default; 
    RemoveDefaultConstruction& operator=(T &&other) { value = std::move(other); return *this; } 
    RemoveDefaultConstruction& operator=(T const &other) { value = other; return *this; } 

    T const &get() const { return value; } // Keep const correctness 
    T &get() { return value; } // Keep const correctness 
}; 

void update(std::map<int, RemoveDefaultConstruction<int>> &m, int k, int v) { m.at(k) = v; } 
void update(std::map<int, RemoveDefaultConstruction<int>> const &m, int k, int v) { 
    //m.at(k) = v; // ERROR: Cannot change a const value 
} 

Live Demo

संबंधित मुद्दे