স্ট্যান্ড :: হ্যাশ <কী> :: অপারেটর () আনর্ডার্ডযুক্ত পাত্রে ব্যবহারকারীর সংজ্ঞায়িত প্রকারের জন্য কীভাবে বিশেষজ্ঞ?


101

ব্যবহারকারী-সংজ্ঞায়িত কী ধরনের সমর্থন করার জন্য std::unordered_set<Key>এবং std::unordered_map<Key, Value> এক প্রদান করেছেন operator==(Key, Key)এবং একটি হ্যাশ functor:

struct X { int id; /* ... */ };
bool operator==(X a, X b) { return a.id == b.id; }

struct MyHash {
  size_t operator()(const X& x) const { return std::hash<int>()(x.id); }
};

std::unordered_set<X, MyHash> s;

টাইপ করার জন্য কেবল std::unordered_set<X> একটি ডিফল্ট হ্যাশ দিয়ে লিখতে আরও সুবিধাজনক হবে Xযেমন সংকলক এবং লাইব্রেরির সাথে আসা প্রকারের জন্য। পরামর্শের পরে

  • সি ++ স্ট্যান্ডার্ড খসড়া N3242 §20.8.12 [আনর্ডর্ড.হ্যাশ] এবং .617.6.3.4 [হ্যাশ.রঙ্কিয়মেন্টস],
  • Boost.Unordered
  • g ++ include\c++\4.7.0\bits\functional_hash.h
  • ভিসি 10 include\xfunctional
  • স্ট্যাক ওভারফ্লোতে বিভিন্ন সম্পর্কিত প্রশ্ন

এটি বিশেষজ্ঞ করা সম্ভব বলে মনে হচ্ছে std::hash<X>::operator():

namespace std { // argh!
  template <>
  inline size_t 
  hash<X>::operator()(const X& x) const { return hash<int>()(x.id); } // works for MS VC10, but not for g++
  // or
  // hash<X>::operator()(X x) const { return hash<int>()(x.id); }     // works for g++ 4.7, but not for VC10 
}                                                                             

সি ++ 11 এর জন্য প্রদত্ত সংকলক সমর্থনটি এখনও পরীক্ষামূলক --- আমি ঝাঁকুনির চেষ্টা করিনি --- এগুলি আমার প্রশ্ন:

  1. নেমস্পেসে এই জাতীয় বিশেষত্ব যুক্ত করা কি আইনী std? সে সম্পর্কে আমার মিশ্র অনুভূতি আছে।

  2. std::hash<X>::operator()সংস্করণগুলির মধ্যে কোনটি সি ++ 11 স্ট্যান্ডার্ডের সাথে সামঞ্জস্যপূর্ণ?

  3. এটি করার কোনও পোর্টেবল উপায় আছে কি?


জিসিসি 4.7.2 সহ, আমাকে একটি গ্লোবাল সরবরাহ করতে হয়েছিলoperator==(const Key, const Key)
ভিক্টর লিউবস্লাভস্কি

নোট করুন যে std::hash( stdনামস্থানের অন্যান্য জিনিসের বিপরীতে ) বিশেষীকরণ গুগল স্টাইল গাইড দ্বারা নিরুৎসাহিত করা হয়েছে ; নুনের এক দানা দিয়ে এটি গ্রহণ করুন।
ফ্রাঙ্কলিন ইউ

উত্তর:


128

আপনাকে নাম স্পেসে * বিশেষায়িতকরণ যুক্ত করার জন্য স্পষ্টভাবে অনুমতি দেওয়া এবং উত্সাহিত করা হয় std। হ্যাশ ফাংশন যুক্ত করার সঠিক (এবং মূলত কেবল) উপায়টি হ'ল:

namespace std {
  template <> struct hash<Foo>
  {
    size_t operator()(const Foo & x) const
    {
      /* your code here, e.g. "return hash<int>()(x.value);" */
    }
  };
}

(অন্যান্য জনপ্রিয় বিশেষায়িত আপনি সমর্থন বিবেচনা করতে পারেন হয় std::less, std::equal_toএবং std::swap।)

*) যতক্ষণ না জড়িত প্রকারগুলির মধ্যে একটি ব্যবহারকারী-সংজ্ঞায়িত হয়, আমি মনে করি।


4
এটি সম্ভব হওয়ার পরে, আপনি কি সাধারণত এইভাবে এটি করার পরামর্শ দিন? আমি এর unorder_map<eltype, hash, equality>পরিবর্তে ইনস্ট্যান্টেশন পছন্দ করব , মজাদার এডিএল ব্যবসায়ের সাথে কারও দিন নষ্ট করা এড়াতে। ( সম্পাদনা পিট বেকার এর এই বিষয়ে পরামর্শ )
sehe

4
@ সেহ: আপনার যদি একটি হ্যাশ ফান্টার পড়ে থাকে তবে এটি ডিফল্ট-গঠনমূলক, সম্ভবত, তবে কেন? (সমতা সহজ, যেহেতু আপনি কেবল সদস্যকে বাস্তবায়ন করতেন operator==।) আমার সাধারণ দর্শনটি হ'ল যদি ফাংশনটি প্রাকৃতিক এবং মূলত কেবলমাত্র "সঠিক" এক হয় (তেমন লেক্সিকোগ্রাফিক জুটির তুলনায়) তবে আমি এটিতে যুক্ত করব std। যদি এটি অদ্ভুত কিছু হয় (যেমন আনর্ডার্ড জোড় তুলনা) তবে আমি এটি একটি ধারক প্রকারের সাথে নির্দিষ্ট করে তুলি।
কেরেরেক এসবি

4
আমি দ্বিমত পোষণ করছি না, তবে স্ট্যান্ডার্ডে বিশেষত্ব যুক্ত করার জন্য আমাদের কোথায় স্ট্যান্ডার্ডে অনুমতি দেওয়া এবং উত্সাহ দেওয়া হয়?
রাজেহ

4
@ কেরেক, আমি একমত, তবে আমি মানের কোনও জায়গার জন্য একটি অধ্যায় এবং শ্লোকের রেফারেন্সের জন্য আশা করছিলাম। আমি ইঞ্জেকশনটিকে ১.6..6.৪.২.১ এ অনুমতি দিয়ে শব্দটি খুঁজে পেয়েছি যেখানে এটি বলেছে যে "অন্যথায় নির্দিষ্ট না করা" ছাড়া এটি অনুমোদিত নয়, তবে আমি 4000+ পৃষ্ঠার নির্দিষ্টকরণের মধ্যে "অন্যথায় নির্দিষ্ট" অংশটি পাইনি।
রাজেহ

4
@ রাজেহ আপনি এখানে পড়তে পারেন "কোনও প্রোগ্রাম কোনও স্ট্যান্ডার্ড লাইব্রেরি টেম্পলেটের জন্য নাম স্পেসে একটি টেম্পলেট বিশেষায়নের যোগ করতে পারে কেবলমাত্র যদি ঘোষণাটি কোনও ব্যবহারকারী-সংজ্ঞায়িত প্রকারের উপর নির্ভর করে এবং বিশেষত্বটি মূল টেমপ্লেটের জন্য স্ট্যান্ডার্ড লাইব্রেরির প্রয়োজনীয়তা পূরণ করে এবং স্পষ্টভাবে নিষিদ্ধ না হয় । "। সুতরাং এই সমাধান ঠিক আছে।
মেরেক আর

7

আমার বাজিটি আনর্ডার্ড_ম্যাপ / আনর্ডার_সেট / ... শ্রেণীর জন্য হ্যাশ টেম্পলেট যুক্তিতে থাকবে:

#include <unordered_set>
#include <functional>

struct X 
{
    int x, y;
    std::size_t gethash() const { return (x*39)^y; }
};

typedef std::unordered_set<X, std::size_t(*)(const X&)> Xunset;
typedef std::unordered_set<X, std::function<std::size_t(const X&)> > Xunset2;

int main()
{
    auto hashX = [](const X&x) { return x.gethash(); };

    Xunset  my_set (0, hashX);
    Xunset2 my_set2(0, hashX); // if you prefer a more flexible set typedef
}

অবশ্যই

  • হ্যাশএক্স ঠিক একইভাবে একটি বিশ্বব্যাপী স্ট্যাটিক ফাংশন হতে পারে
  • দ্বিতীয় ক্ষেত্রে, আপনি এটি পাস করতে পারে
    • পুরানো ফ্যাশনযুক্ত ফান্টর অবজেক্ট ( struct Xhasher { size_t operator(const X&) const; };)
    • std::hash<X>()
    • স্বাক্ষর সন্তুষ্ট যে কোনও বাঁধাই প্রকাশ -

আমি প্রশংসা করি যে আপনি এমন কিছু লিখতে পারেন যার ডিফল্ট নির্মাতা নেই, তবে আমি সর্বদা খুঁজে পাই যে প্রতিটি মানচিত্রের নির্মাণের অতিরিক্ত যুক্তি মনে রাখার প্রয়োজন হয় এটি একটি ভারী বোঝা - আমার স্বাদের জন্য বেশ কিছুটা বোঝা। আমি স্পষ্টতালীন টেমপ্লেট যুক্তির সাথে ঠিক আছি, যদিও বিশেষায়িত std::hashহওয়া এখনও সবচেয়ে
উত্তম

উদ্ধারকারীর জন্য ব্যবহারকারী-সংজ্ঞায়িত প্রকারগুলি :-) আরও গুরুতরভাবে, আমি আশা করি আমরা ইতিমধ্যে তাদের মস্তকে কব্জিতে চড় মারব যেখানে তাদের শ্রেণিতে একটি রয়েছে char*!
কেরেরেক এসবি

হুঁ ... কীভাবে কোনও hashবিশেষায়নের মাধ্যমে এডিএল হস্তক্ষেপ করা যায় তার একটি উদাহরণ আছে ? আমি বোঝাতে চাইছি এটি সম্পূর্ণরূপে প্রশংসনীয়, তবে একটি সমস্যা ক্ষেত্রে আসার জন্য আমার খুব কষ্ট হয়েছে।
কেরেক এসবি


যতক্ষণ না আপনার প্রয়োজন std::unordered_map<Whatever, Xunset>লাগে এবং এটি কাজ করে না Xunsetততক্ষণ এগুলি সমস্ত মজাদার এবং গেমস কারণ আপনার হ্যাশার ধরণটি ডিফল্ট গঠনযোগ্য নয়।
ব্রায়ান গর্ডন

4

@ কেরেক এসবি কভার করেছেন 1) এবং 3)।

2) যদিও জি ++ এবং ভিসি 10 std::hash<T>::operator()বিভিন্ন স্বাক্ষর সহ ঘোষণা করে, উভয় গ্রন্থাগার বাস্তবায়ন স্ট্যান্ডার্ড সম্মতিযুক্ত।

স্ট্যান্ডার্ড এর সদস্যদের নির্দিষ্ট করে না std::hash<T>। এটি কেবলমাত্র বলে যে এই জাতীয় প্রতিটি বিশেষায়নের জন্য দ্বিতীয় টেমপ্লেট যুক্তির জন্য প্রয়োজনীয় "হ্যাশ" প্রয়োজনীয়তাগুলি অবশ্যই মেটানো উচিত std::unordered_set। যথা:

  • হ্যাশ টাইপ Hএকটি ফাংশন অবজেক্ট, কমপক্ষে একটি আর্গুমেন্ট টাইপ সহ Key
  • H কপি গঠনযোগ্য।
  • H ধ্বংসাত্মক।
  • তাহলে hপ্রকারের একটি অভিব্যক্তি Hবা const H, এবং kথেকে (সম্ভবত পরিবর্তনীয় একটি টাইপ একটি অভিব্যক্তি const) Key, তারপর h(k)টাইপ এর সাথে একটি বৈধ অভিব্যক্তি size_t
  • যদি hটাইপের একটি এক্সপ্রেশন Hবা const H, এবং টাইপের uএকটি মূল্যমান হয় Key, তবে h(u)প্রকারের সাথে একটি বৈধ এক্সপ্রেশন size_tযা কোনও সংশোধন করে না u

না, উভয়ই বাস্তবায়ন মানসম্পন্ন নয়, যেহেতু তারা সামগ্রিকের std::hash<X>::operator()চেয়ে বিশেষতীকরণের চেষ্টা করে std::hash<X>এবং এর স্বাক্ষর std::hash<T>::operator()বাস্তবায়ন-সংজ্ঞায়িত।
iljarn

@ ইল্ডার্ন: স্পষ্ট হয়েছে - আমি লাইব্রেরি বাস্তবায়নের কথা বলছিলাম, বিশেষায়িত প্রচেষ্টা নয়। নিশ্চিত না যে ওপিটি ঠিক কী জিজ্ঞাসা করেছিল।
aschepler
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.