2010-02-25 21 views
52

क्या कोई कुंजी मौजूद नहीं है जब डिफ़ॉल्ट मान std::map के operator[] रिटर्न निर्दिष्ट करने का कोई तरीका है?std :: नक्शा डिफ़ॉल्ट मान

+0

इस आम निर्माण पर्ल में बहुत ही सुंदर है: 'मेरी $ वैल = $ मानचित्र {" कुंजी " }: "एनएएन" ' –

उत्तर

34

नहीं, ऐसा नहीं है। ऐसा करने के लिए सबसे आसान समाधान अपने स्वयं के नि: शुल्क टेम्पलेट फ़ंक्शन लिखना है। कुछ की तरह:

#include <string> 
#include <map> 
using namespace std; 

template <typename K, typename V> 
V GetWithDef(const std::map <K,V> & m, const K & key, const V & defval) { 
    typename std::map<K,V>::const_iterator it = m.find(key); 
    if (it == m.end()) { 
     return defval; 
    } 
    else { 
     return it->second; 
    } 
} 

int main() { 
    map <string,int> x; 
    ... 
    int i = GetWithDef(x, string("foo"), 42); 
} 

सी ++ 11 अद्यतन

उद्देश्य: सामान्य साहचर्य कंटेनर, साथ ही वैकल्पिक तुलनित्र और संभाजक मापदंडों के लिए खाते।

template <template<class,class,class...> class C, typename K, typename V, typename... Args> 
V GetWithDef(const C<K,V,Args...>& m, K const& key, const V & defval) 
{ 
    typename C<K,V,Args...>::const_iterator it = m.find(key); 
    if (it == m.end()) 
     return defval; 
    return it->second; 
} 
+1

अच्छा समाधान है। हो सकता है कि आप कुछ टेम्पलेट तर्क जोड़ना चाहें ताकि फ़ंक्शन टेम्पलेट उन मानचित्रों के साथ काम करता है जो तुलनित्र और आवंटक के लिए डिफ़ॉल्ट टेम्पलेट पैरामीटर का उपयोग नहीं करते हैं। – sbi

+3

+1, लेकिन सटीक वही व्यवहार प्रदान करने के लिए 'ऑपरेटर []' को डिफ़ॉल्ट मान के साथ, डिफ़ॉल्ट मान को 'if (it == m.end())' ब्लॉक –

+12

@ डेविड के अंदर मानचित्र में डाला जाना चाहिए मुझे लगता है कि ओपी वास्तव में उस व्यवहार को नहीं चाहता है। मैं कॉन्फ़िगरेशन पढ़ने के लिए एक समान योजना का उपयोग करता हूं, लेकिन मैं नहीं चाहता कि कोई कुंजी गुम हो तो कॉन्फ़िगरेशन अपडेट हो। –

3

डिफ़ॉल्ट मान निर्दिष्ट करने का कोई तरीका नहीं है - यह हमेशा डिफ़ॉल्ट (शून्य पैरामीटर कन्स्ट्रक्टर) द्वारा निर्मित मान होता है।

वास्तव में operator[] शायद आप अपेक्षा करते हैं कि मानचित्र में दी गई कुंजी के लिए कोई मान मौजूद नहीं है, तो यह डिफ़ॉल्ट कन्स्ट्रक्टर से मूल्य के साथ एक नया डालेगा।

+2

सही, नई प्रविष्टियों को जोड़ने से बचने के लिए आप 'ढूंढ' का उपयोग कर सकते हैं जो किसी दिए गए कुंजी के लिए कोई तत्व मौजूद नहीं होने पर एंड इटेटरेटर लौटाता है। –

1

शायद आप एक कस्टम आवंटक दे सकते हैं जो आपके इच्छित डिफ़ॉल्ट मान के साथ आवंटित करता है।

template < class Key, class T, class Compare = less<Key>, 
     class Allocator = allocator<pair<const Key,T> > > class map; 
+4

'ऑपरेटर []' 'टी()' का आह्वान करके बनाई गई ऑब्जेक्ट देता है, इससे कोई फर्क नहीं पड़ता कि आवंटक क्या करता है। – sbi

+1

@ एसबीआई: क्या नक्शा आवंटकों की 'निर्माण' विधि को कॉल नहीं करता है? यह बदलना संभव होगा, मुझे लगता है। मुझे एक 'निर्माण' समारोह पर संदेह है जो 'नया (पी) टी (टी) के अलावा कुछ नहीं करता है, हालांकि, अच्छी तरह से गठित नहीं है। संपादित करें: मूर्खतापूर्ण बात जो मूर्ख थी, अन्यथा सभी मूल्य समान होंगे: पी मेरी कॉफी कहां है ... – GManNickG

+1

@GMan: सी ++ 03 की मेरी प्रति कहती है (23.3.1.2 में) कि 'ऑपरेटर [] 'रिटर्न' (* ((डालें (make_pair (x, टी()))) पहले))। दूसरा'। तो जब तक मुझे कुछ याद नहीं आ रहा है, तो यह जवाब गलत है। – sbi

10

सी ++ मानक (23.3.1.2) निर्दिष्ट करता है कि नव डाला मान डिफ़ॉल्ट का निर्माण किया है, इसलिए map ही यह करने का एक तरीका प्रदान नहीं करता है। आपके विकल्प हैं:

  • मूल्य एक डिफ़ॉल्ट निर्माता है कि यह आप चाहते हैं मूल्य के लिए initialises, या
  • लपेटें नक्शा अपनी खुद की कक्षा में जिसका कोई डिफ़ॉल्ट मान प्रदान करता है और operator[] लागू करता है कि डिफ़ॉल्ट सम्मिलित करने के लिए टाइप करें।
+6

ठीक है, नए डालने वाले मान को सटीक मानने के लिए मूल्य प्रारंभ किया गया है (8.5.5) तो: - यदि टी उपयोगकर्ता द्वारा घोषित कन्स्ट्रक्टर (12.1) वाला क्लास प्रकार है, तो टी के लिए डिफ़ॉल्ट कन्स्ट्रक्टर को (और यदि टी में कोई सुलभ डिफ़ॉल्ट कन्स्ट्रक्टर नहीं है तो प्रारंभिकता खराब हो जाती है); - यदि टी उपयोगकर्ता द्वारा घोषित कन्स्ट्रक्टर के बिना एक गैर-यूनियन क्लास प्रकार है, तो टी के प्रत्येक गैर स्थैतिक डेटा सदस्य और बेसक्लास घटक मूल्य-प्रारंभिक है; - यदि टी एक सरणी प्रकार है, तो प्रत्येक तत्व मान-प्रारंभिक है; - अन्यथा, ऑब्जेक्ट शून्य-प्रारंभिक –

4
template<typename T, T X> 
struct Default { 
    Default() : val(T(X)) {} 
    Default (T const & val) : val(val) {} 
    operator T &() { return val; } 
    operator T const &() const { return val; } 
    T val; 
}; 

<...> 

std::map<KeyType, Default<ValueType, DefaultValue> > mapping; 
+0

स्ट्रिंग, और शाब्दिक के साथ प्रयास करें। यह काम नहीं करता है। –

+2

फिर इसे संशोधित करें ताकि यह काम करे। मैं इस मामले को पूरा करने के लिए डिज़ाइन नहीं किया गया था, इस मामले को ठीक करने के लिए परेशान नहीं होने वाला हूं। –

2

मूल्य, डिफ़ॉल्ट निर्माता का उपयोग कर आरंभ नहीं हो जाता के रूप में अन्य उत्तर का कहना है। हालांकि, यह सरल प्रकारों (इंटीग्रल प्रकार जैसे इंट, फ्लोट, पॉइंटर या पीओडी (पुराने डेटा की योजना) प्रकारों के मामले में जोड़ने के लिए उपयोगी है), मान शून्य-प्रारंभिक होते हैं (या मूल्य-प्रारंभिकरण द्वारा शून्य (जो प्रभावी रूप से प्रभावी होता है) वही बात), सी ++ के किस संस्करण का उपयोग किया जाता है)।

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

std::map<int, char*> map; 
typedef char *P; 
char *p = map[123], 
    *p1 = P(); // map uses the same construct inside, causes zero-initialization 
assert(!p && !p1); // both will be 0 

इस मामले पर अधिक जानकारी के लिए Do the parentheses after the type name make a difference with new? देखें।

4

अधिक सामान्य संस्करण, समर्थन सी ++ 98/03 और अधिक कंटेनरों सामान्य साहचर्य कंटेनर के साथ

काम करता है, केवल टेम्पलेट पैरामीटर कंटेनर प्रकार ही है।

समर्थित कंटेनर: std::map, std::multimap, std::unordered_map, std::unordered_multimap, wxHashMap, QMap, QMultiMap, QHash, QMultiHash, आदि

template<typename MAP> 
const typename MAP::mapped_type& get_with_default(const MAP& m, 
              const typename MAP::key_type& key, 
              const typename MAP::mapped_type& defval) 
{ 
    typename MAP::const_iterator it = m.find(key); 
    if (it == m.end()) 
     return defval; 

    return it->second; 
} 

उपयोग:

std::map<int, std::string> t; 
t[1] = "one"; 
string s = get_with_default(t, 2, "unknown"); 

यहाँ, एक आवरण वर्ग का उपयोग कर जो अधिक विधि dict प्रकार के get() अजगर में के समान है द्वारा एक समान कार्यान्वयन: https://github.com/hltj/wxMEdit/blob/master/src/xm/xm_utils.hpp

template<typename MAP> 
struct map_wrapper 
{ 
    typedef typename MAP::key_type K; 
    typedef typename MAP::mapped_type V; 
    typedef typename MAP::const_iterator CIT; 

    map_wrapper(const MAP& m) :m_map(m) {} 

    const V& get(const K& key, const V& default_val) const 
    { 
     CIT it = m_map.find(key); 
     if (it == m_map.end()) 
      return default_val; 

     return it->second; 
    } 
private: 
    const MAP& m_map; 
}; 

template<typename MAP> 
map_wrapper<MAP> wrap_map(const MAP& m) 
{ 
    return map_wrapper<MAP>(m); 
} 

उपयोग:

std::map<int, std::string> t; 
t[1] = "one"; 
string s = wrap_map(t).get(2, "unknown"); 
13

हालांकि यह वास्तव में इस सवाल का जवाब नहीं है, मैं इस तरह कोड के साथ समस्या यह उन्हें धोखा दिया है:

struct IntDefaultedToMinusOne 
{ 
    int i = -1; 
}; 

std::map<std::string, IntDefaultedToMinusOne > mymap; 
0

सी ++ 17 जो वास्तव में यह करता है try_emplace प्रदान करता है। यह मूल्य निर्माता के लिए एक महत्वपूर्ण और एक तर्क सूची लेता है और एक जोड़ी देता है: एक iterator और एक bool:। http://en.cppreference.com/w/cpp/container/map/try_emplace

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