std :: মানচিত্রের ডিফল্ট মান


89

সেখানে ডিফল্ট মান নির্দিষ্ট করার একটি উপায় আছে কি std::map'র operator[]একটি কী বিদ্যমান নেই যখন আয়?

উত্তর:


58

না, নেই। এর সহজ সমাধান হ'ল এটি করার জন্য আপনার নিজের ফ্রি টেমপ্লেট ফাংশনটি লিখুন। কিছুটা এইরকম:

#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 আপডেট

উদ্দেশ্য: জেনেরিক অ্যাসোসিয়েটিভ ধারকগুলির জন্য অ্যাকাউন্ট, পাশাপাশি alচ্ছিক তুলনামূলক এবং বরাদ্দকারী পরামিতি।

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

4
সুন্দর সমাধান। আপনি কয়েকটি টেম্পলেট যুক্তি যুক্ত করতে চাইতে পারেন যাতে ফাংশন টেম্পলেটটি মানচিত্রের সাথে কাজ করে যা তুলনকারী এবং বরাদ্দকারীদের জন্য ডিফল্ট টেম্পলেট পরামিতি ব্যবহার করে না।
sbi

4
+1, কিন্তু operator[]ডিফল্ট মান হিসাবে ঠিক একই আচরণ প্রদানের জন্য , ডিফল্ট মানটি if ( it == m.end() )ব্লকের অভ্যন্তরে মানচিত্রে প্রবেশ করাতে হবে
ডেভিড রদ্রিগেজ - ড্রিবিস

13
@ ডেভিড আমি ধরে নিচ্ছি যে ওপি আসলে আচরণটি চায় না। আমি কনফিগারেশন পড়ার জন্য অনুরূপ স্কিম ব্যবহার করি, তবে কোনও কী অনুপস্থিত থাকলে কনফিগারেশনটি আপডেট করতে চাই না।

4
@GMan bool প্যারামিটারগুলি কিছু লোক খারাপ স্টাইল বলে মনে করে কারণ আপনি কলটি (ঘোষণার বিপরীতে) তারা কী করে তা দেখে বলতে পারবেন না - এই ক্ষেত্রে "সত্য" এর অর্থ "ডিফল্ট ব্যবহার" বা "ডন" হয় না? ডিফল্ট ব্যবহার করবেন না "(বা পুরোপুরি অন্য কিছু)? একটি এনাম সবসময় পরিষ্কার হয় তবে অবশ্যই আরও কোড থাকে। আমি নিজেই এই বিষয়ে দুটি মনে রয়েছি।

4
তাহলে ডিফল্ট মান nullptr, কিন্তু এই উত্তর কাজ করে না stackoverflow.com/a/26958878/297451 আছে।
জন

45

যদিও এটি প্রশ্নের সঠিক উত্তর দেয় না, আমি কোডটির মতো সমস্যাটি সমাধান করেছি:

struct IntDefaultedToMinusOne
{
    int i = -1;
};

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

4
এটি আমার পক্ষে সেরা সমাধান। কার্যকর করা খুব সহজ, খুব নমনীয় এবং জেনেরিক।
এজেসস

11

সি ++ স্ট্যান্ডার্ড (২৩.৩.১.২) সুনির্দিষ্ট করে যে সদ্য সন্নিবেশ করা মানটি পূর্বনির্ধারিত, তাই mapনিজেই এটি করার কোনও উপায় সরবরাহ করে না। আপনার পছন্দগুলি হ'ল:

  • মানের ধরণটিকে একটি ডিফল্ট নির্মাতা দিন যা এটি আপনার যে মানটি বা এটি চান তার সাথে শুরু করে
  • আপনার নিজের শ্রেণিতে মানচিত্রটি মুড়ে দিন যা একটি ডিফল্ট মান সরবরাহ করে এবং operator[]সেই ডিফল্টটি সন্নিবেশ করানোর জন্য প্রয়োগ করে।

8
ঠিক আছে, সদ্য সন্নিবেশ করা মানটি হ'ল মান (8.5.5) হয় তাই: - টি যদি কোনও ব্যবহারকারী-ঘোষিত কনস্ট্রাক্টর (12.1) সহ শ্রেণীর ধরণের হয় তবে টি এর জন্য ডিফল্ট কনস্ট্রাক্টর বলা হয় (এবং প্রারম্ভিককরণ অসুস্থ) -ভেদযুক্ত যদি টি এর অ্যাক্সেসযোগ্য ডিফল্ট নির্মাণকারী নেই); - যদি টি কোনও ব্যবহারকারী-ঘোষিত কনস্ট্রাক্টর ছাড়াই নন-ইউনিয়ন শ্রেণীর ধরণ হয়, তবে প্রতিটি অ স্থিতিশীল ডেটা সদস্য এবং টি এর বেসক্লাস উপাদানটি মান-আরম্ভ হয়; - যদি টি একটি অ্যারের ধরণ হয় তবে প্রতিটি উপাদান মান-আরম্ভ হয়; - অন্যথায়, অবজেক্টটি শূন্য-
সূচনাযুক্ত

7

সি ++ 17 প্রদান করে try_emplaceযা ঠিক এটি করে। এটি মান নির্মাতার জন্য একটি কী এবং যুক্তি তালিকার জন্য নেয় এবং একটি জোড়া দেয়: একটি iteratorএবং একটি bool: http://en.cppreferences.com/w/cpp/container/map/ry_emplace


6

আরও সাধারণ সংস্করণ, সি ++ 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");

এখানে একটি র‌্যাপার ক্লাস ব্যবহার করে অনুরূপ প্রয়োগ করা হচ্ছে, যা পাইথনে টাইপ পদ্ধতির get()সাথে আরও dictসাদৃশ্য: 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");

এমএপি :: ম্যাপযুক্ত_প্রকার এবং টাইপনেম এমএপি :: ম্যাপযুক্ত_প্রকার ও ডিফলাল সুযোগের বাইরে থাকতে পারে বলে ফিরে আসা নিরাপদ নয়।
জো সি

5

ডিফল্ট মান নির্দিষ্ট করার কোনও উপায় নেই - এটি সর্বদা মান ডিফল্ট দ্বারা নির্মিত (শূন্য পরামিতি নির্মাণকারী) is

প্রকৃতপক্ষে operator[]সম্ভবত আপনি প্রত্যাশার চেয়ে আরও বেশি কিছু করেছেন যেন মানচিত্রে প্রদত্ত কীটির জন্য কোনও মান বিদ্যমান না থাকলে এটি ডিফল্ট কনস্ট্রাক্টরের মান সহ একটি নতুন সন্নিবেশ করবে।


4
ঠিক আছে, নতুন এন্ট্রিগুলি এড়াতে আপনি ব্যবহার করতে পারেন findযা প্রদত্ত কীটির জন্য কোনও উপাদান উপস্থিত না থাকলে শেষ পুনরাবৃত্তিকে ফেরত দেয়।
থমাস শ্যাউব

@ থমাসচ্যাব findসেই ক্ষেত্রে সময়ের জটিলতা কত ?
অজয়সিংহেঙ্গি

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

4
তারপরে এটি পরিবর্তন করুন যাতে এটি কাজ করে। আমি কোনও মামলা ঠিক করার জন্য বিরক্ত করব না এই কোডটি সম্পাদনের জন্য ডিজাইন করা হয়নি।
টমাস এডিং

3

অন্যান্য উত্তরগুলি বলে মানটি ডিফল্ট নির্মাণকারী ব্যবহার করে শুরু করা হয়। তবে এটি যুক্ত করা দরকারী যে সরল প্রকারের (ইন্টিগ্রাল টাইপ যেমন ইন্টি, ফ্লোট, পয়েন্টার বা পিওডি (পুরাতন ডেটা পরিকল্পনা) প্রকারের ক্ষেত্রে) মানগুলি শূন্য-আরম্ভ হয় (বা মান-শুরুর মাধ্যমে শূন্য হয়) যা কার্যকরভাবে হয় একই জিনিস), সি ++ এর কোন সংস্করণ ব্যবহৃত হবে তার উপর নির্ভর করে)।

যাইহোক, মূল কথাটি হ'ল, সাধারণ ধরণের মানচিত্রগুলি স্বয়ংক্রিয়ভাবে নতুন আইটেমগুলিকে শূন্য-আরম্ভ করবে। সুতরাং কিছু ক্ষেত্রে, ডিফল্ট প্রাথমিক মানটি স্পষ্টভাবে উল্লেখ করার বিষয়ে চিন্তা করার দরকার নেই।

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

দেখুন কি টাইপ নামের পরে প্রথম বন্ধনী নতুন একটি পার্থক্য করতে? বিষয়টি সম্পর্কে আরও তথ্যের জন্য।


2

এর map::at()পরিবর্তে ব্যবহারের জন্য একটি কাজ []। যদি একটি কী উপস্থিত না থাকে,at একটি ব্যতিক্রম ছুঁড়ে দেয়। এমনকি ভাল, এটি ভেক্টরদের জন্যও কাজ করে এবং এটি জেনেরিক প্রোগ্রামিংয়ের জন্য উপযুক্ত যেখানে আপনি কোনও ভেক্টর দিয়ে মানচিত্রটি অদলবদল করতে পারেন।

নিবন্ধভুক্ত কীগুলির জন্য একটি কাস্টম মান ব্যবহার করা বিপজ্জনক হতে পারে যেহেতু সেই কাস্টম মানটি (যেমন -1) কোডে আরও নিচে প্রক্রিয়া করা হতে পারে। ব্যতিক্রম সহ, বাগগুলি খুঁজে পাওয়া সহজ।


1

হতে পারে আপনি একটি কাস্টম বরাদ্দকারী দিতে পারেন যিনি আপনার চান ডিফল্ট মান দিয়ে বরাদ্দ করেন।

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

4
operator[]ডিগ্রিদানকারীর দ্বারা তৈরি করা কোনও বস্তু প্রদান করে T(), বরাদ্দকারী যাই করুক না কেন।
এসবিআই

4
@ এসবিআই: মানচিত্র কি বরাদ্দকারী constructপদ্ধতিতে কল দেয় না ? এটা যে পরিবর্তন করা সম্ভব হবে, আমি মনে করি। যদিও আমি constructএমন কোনও ফাংশন সন্দেহ করি যা এর চেয়ে সুষ্ঠুভাবে তৈরি না হয়ে অন্য কিছু করে new(p) T(t);। সম্পাদনা: অন্ধকারে যা বোকামি, অন্যথায় সমস্ত মান একই হবে: পি আমার কফি কোথায় ...
GManNickG

4
@ জিএমান: আমার সি ++ 03 এর অনুলিপিটি জানিয়েছে (23.3.1.2 এ) যা operator[]ফিরে আসে (*((insert(make_pair(x, T()))).first)).second। সুতরাং আমি যদি কিছু মিস না করি তবে এই উত্তরটি ভুল।
sbi

তুমি ঠিক. তবে সেটা আমার কাছে ভুল বলে মনে হচ্ছে। কেন তারা theোকানোর জন্য বরাদ্দ ফাংশন ব্যবহার করবেন না?
ভিডিভিএলিয়ন

4
@ এসবিআই: না, আমি এই উত্তরটি ভুল বলে সম্মত, তবে ভিন্ন কারণে। কম্পাইলার প্রকৃতপক্ষে করে insertএকটি সঙ্গে T(), কিন্তু এটি একটি নতুন জন্য বরাদ্দকরণ পেতে মেমরির ব্যবহার করবে ভিতরে সন্নিবেশ হয় Tতারপর কল constructপ্যারামিটার এটা দেওয়া হয়েছিল, যা যে মেমরিতে T()। সুতরাং এটি operator[]অন্যরকম কিছু ফিরিয়ে আনার আচরণের পরিবর্তন করা সম্ভব , তবে বরাদ্দকারী কেন এটি ডাকা হচ্ছে তা পার্থক্য করতে পারে না। এমনকি যদি আমরা constructএটির পরামিতিটিকে উপেক্ষা করে আমাদের বিশেষ মানটি তৈরি করি, তার অর্থ প্রতিটি নির্মিত উপাদানটির সেই মান ছিল যা খারাপ is
GManNickG

1

উত্তরে সম্প্রসারিত https://stackoverflow.com/a/2333816/272642 , এই টেমপ্লেটটি ফাংশন ব্যবহার std::mapএর key_typeএবং mapped_typetypedefs ধরণ অনুমান করতে keyএবং def। এই টাইপডেফগুলি ছাড়া পাত্রে এটি কাজ করে না।

template <typename C>
typename C::mapped_type getWithDefault(const C& m, const typename C::key_type& key, const typename C::mapped_type& def) {
    typename C::const_iterator it = m.find(key);
    if (it == m.end())
        return def;
    return it->second;
}

এটি আপনাকে ব্যবহার করতে দেয়

std::map<std::string, int*> m;
int* v = getWithDefault(m, "a", NULL);

প্রয়োজন মতো আর্গুমেন্ট কাস্ট করার দরকার নেই std::string("a"), (int*) NULL


1

ব্যবহার std::map::insert()

এই পার্টিতে আমি বেশ দেরি করেই বুঝতে পেরেছি, তবে আপনি যদি operator[]কাস্টম ডিফল্টের সাথে আচরণের বিষয়ে আগ্রহী হন (অর্থাত্ প্রদত্ত কীটি দিয়ে উপাদানটি সন্ধান করুন, যদি তা উপস্থিত না থাকে তবে মানচিত্রে একটি উপাদান প্রবেশ করান) ডিফল্ট মানটি বেছে নেওয়া হয়েছে এবং সদ্য সন্নিবেশ করা মান বা বিদ্যমান মান হয় একটি রেফারেন্স ফিরিয়ে দিন), ইতিমধ্যে সি ++ 17: এর পূর্বে আপনার জন্য একটি ফাংশন উপলব্ধ std::map::insert()insertকীটি ইতিমধ্যে উপস্থিত থাকলে প্রকৃতপক্ষে সন্নিবেশ করা হবে না, পরিবর্তে বিদ্যমান মানটিতে একটি পুনরাবৃত্তি ফিরিয়ে দিন।

বলুন, আপনি স্ট্রিং-টু-ইন্টের মানচিত্র চেয়েছিলেন এবং কীটি উপস্থিত না থাকলে 42 এর একটি ডিফল্ট মান সন্নিবেশ করান:

std::map<std::string, int> answers;

int count_answers( const std::string &question)
{
    auto  &value = answers.insert( {question, 42}).first->second;
    return value++;
}

int main() {

    std::cout << count_answers( "Life, the universe and everything") << '\n';
    std::cout << count_answers( "Life, the universe and everything") << '\n';
    std::cout << count_answers( "Life, the universe and everything") << '\n';
    return 0;
}

যা 42, 43 এবং 44 আউটপুট হওয়া উচিত।

মানচিত্রের মান নির্মানের ব্যয় যদি বেশি হয় (তবে কীটি অনুলিপি করা / চালানো বা মানের ধরণটি ব্যয়বহুল), এটি একটি উল্লেখযোগ্য পারফরম্যান্স পেনাল্টিতে আসে, যা আমি মনে করি সি ++ 17 এর সাথে সংশোধিত হবে try_emplace

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.