সেখানে ডিফল্ট মান নির্দিষ্ট করার একটি উপায় আছে কি std::map
'র operator[]
একটি কী বিদ্যমান নেই যখন আয়?
উত্তর:
না, নেই। এর সহজ সমাধান হ'ল এটি করার জন্য আপনার নিজের ফ্রি টেমপ্লেট ফাংশনটি লিখুন। কিছুটা এইরকম:
#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;
}
operator[]
ডিফল্ট মান হিসাবে ঠিক একই আচরণ প্রদানের জন্য , ডিফল্ট মানটি if ( it == m.end() )
ব্লকের অভ্যন্তরে মানচিত্রে প্রবেশ করাতে হবে
যদিও এটি প্রশ্নের সঠিক উত্তর দেয় না, আমি কোডটির মতো সমস্যাটি সমাধান করেছি:
struct IntDefaultedToMinusOne
{
int i = -1;
};
std::map<std::string, IntDefaultedToMinusOne > mymap;
সি ++ স্ট্যান্ডার্ড (২৩.৩.১.২) সুনির্দিষ্ট করে যে সদ্য সন্নিবেশ করা মানটি পূর্বনির্ধারিত, তাই map
নিজেই এটি করার কোনও উপায় সরবরাহ করে না। আপনার পছন্দগুলি হ'ল:
operator[]
সেই ডিফল্টটি সন্নিবেশ করানোর জন্য প্রয়োগ করে।সি ++ 17 প্রদান করে try_emplace
যা ঠিক এটি করে। এটি মান নির্মাতার জন্য একটি কী এবং যুক্তি তালিকার জন্য নেয় এবং একটি জোড়া দেয়: একটি iterator
এবং একটি bool
: http://en.cppreferences.com/w/cpp/container/map/ry_emplace
আরও সাধারণ সংস্করণ, সি ++ 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");
ডিফল্ট মান নির্দিষ্ট করার কোনও উপায় নেই - এটি সর্বদা মান ডিফল্ট দ্বারা নির্মিত (শূন্য পরামিতি নির্মাণকারী) is
প্রকৃতপক্ষে operator[]
সম্ভবত আপনি প্রত্যাশার চেয়ে আরও বেশি কিছু করেছেন যেন মানচিত্রে প্রদত্ত কীটির জন্য কোনও মান বিদ্যমান না থাকলে এটি ডিফল্ট কনস্ট্রাক্টরের মান সহ একটি নতুন সন্নিবেশ করবে।
find
যা প্রদত্ত কীটির জন্য কোনও উপাদান উপস্থিত না থাকলে শেষ পুনরাবৃত্তিকে ফেরত দেয়।
find
সেই ক্ষেত্রে সময়ের জটিলতা কত ?
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;
অন্যান্য উত্তরগুলি বলে মানটি ডিফল্ট নির্মাণকারী ব্যবহার করে শুরু করা হয়। তবে এটি যুক্ত করা দরকারী যে সরল প্রকারের (ইন্টিগ্রাল টাইপ যেমন ইন্টি, ফ্লোট, পয়েন্টার বা পিওডি (পুরাতন ডেটা পরিকল্পনা) প্রকারের ক্ষেত্রে) মানগুলি শূন্য-আরম্ভ হয় (বা মান-শুরুর মাধ্যমে শূন্য হয়) যা কার্যকরভাবে হয় একই জিনিস), সি ++ এর কোন সংস্করণ ব্যবহৃত হবে তার উপর নির্ভর করে)।
যাইহোক, মূল কথাটি হ'ল, সাধারণ ধরণের মানচিত্রগুলি স্বয়ংক্রিয়ভাবে নতুন আইটেমগুলিকে শূন্য-আরম্ভ করবে। সুতরাং কিছু ক্ষেত্রে, ডিফল্ট প্রাথমিক মানটি স্পষ্টভাবে উল্লেখ করার বিষয়ে চিন্তা করার দরকার নেই।
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
দেখুন কি টাইপ নামের পরে প্রথম বন্ধনী নতুন একটি পার্থক্য করতে? বিষয়টি সম্পর্কে আরও তথ্যের জন্য।
এর map::at()
পরিবর্তে ব্যবহারের জন্য একটি কাজ []
। যদি একটি কী উপস্থিত না থাকে,at
একটি ব্যতিক্রম ছুঁড়ে দেয়। এমনকি ভাল, এটি ভেক্টরদের জন্যও কাজ করে এবং এটি জেনেরিক প্রোগ্রামিংয়ের জন্য উপযুক্ত যেখানে আপনি কোনও ভেক্টর দিয়ে মানচিত্রটি অদলবদল করতে পারেন।
নিবন্ধভুক্ত কীগুলির জন্য একটি কাস্টম মান ব্যবহার করা বিপজ্জনক হতে পারে যেহেতু সেই কাস্টম মানটি (যেমন -1) কোডে আরও নিচে প্রক্রিয়া করা হতে পারে। ব্যতিক্রম সহ, বাগগুলি খুঁজে পাওয়া সহজ।
হতে পারে আপনি একটি কাস্টম বরাদ্দকারী দিতে পারেন যিনি আপনার চান ডিফল্ট মান দিয়ে বরাদ্দ করেন।
template < class Key, class T, class Compare = less<Key>,
class Allocator = allocator<pair<const Key,T> > > class map;
operator[]
ডিগ্রিদানকারীর দ্বারা তৈরি করা কোনও বস্তু প্রদান করে T()
, বরাদ্দকারী যাই করুক না কেন।
construct
পদ্ধতিতে কল দেয় না ? এটা যে পরিবর্তন করা সম্ভব হবে, আমি মনে করি। যদিও আমি construct
এমন কোনও ফাংশন সন্দেহ করি যা এর চেয়ে সুষ্ঠুভাবে তৈরি না হয়ে অন্য কিছু করে new(p) T(t);
। সম্পাদনা: অন্ধকারে যা বোকামি, অন্যথায় সমস্ত মান একই হবে: পি আমার কফি কোথায় ...
operator[]
ফিরে আসে (*((insert(make_pair(x, T()))).first)).second
। সুতরাং আমি যদি কিছু মিস না করি তবে এই উত্তরটি ভুল।
insert
একটি সঙ্গে T()
, কিন্তু এটি একটি নতুন জন্য বরাদ্দকরণ পেতে মেমরির ব্যবহার করবে ভিতরে সন্নিবেশ হয় T
তারপর কল construct
প্যারামিটার এটা দেওয়া হয়েছিল, যা যে মেমরিতে T()
। সুতরাং এটি operator[]
অন্যরকম কিছু ফিরিয়ে আনার আচরণের পরিবর্তন করা সম্ভব , তবে বরাদ্দকারী কেন এটি ডাকা হচ্ছে তা পার্থক্য করতে পারে না। এমনকি যদি আমরা construct
এটির পরামিতিটিকে উপেক্ষা করে আমাদের বিশেষ মানটি তৈরি করি, তার অর্থ প্রতিটি নির্মিত উপাদানটির সেই মান ছিল যা খারাপ is
উত্তরে সম্প্রসারিত https://stackoverflow.com/a/2333816/272642 , এই টেমপ্লেটটি ফাংশন ব্যবহার std::map
এর key_type
এবং mapped_type
typedefs ধরণ অনুমান করতে 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
।
ব্যবহার 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
।