inspired antony's williams "c++ concurrency in action" wanted take closed @ thread safe hash map. copied code , added output operators , came with:
#include <boost/thread/shared_mutex.hpp> #include <functional> #include <list> #include <mutex> #include <iostream> template <typename key, typename value, typename hash = std::hash<key>> class thread_safe_hashmap { private: class bucket_type { public: typedef std::pair<key, value> bucket_value; typedef std::list<bucket_value> bucket_data; typedef typename bucket_data::iterator bucket_iterator; bucket_data data; mutable boost::shared_mutex mutex; bucket_iterator find_entry_for(const key& key) const { return std::find_if(data.begin(), data.end(), [&](const bucket_value& item) { return item.first == key; }); } public: void add_or_update_mapping(key const& key, value const& value) { std::unique_lock<boost::shared_mutex> lock(mutex); bucket_iterator found_entry = find_entry_for(key); if (found_entry == data.end()) { data.push_back(bucket_value(key, value)); } else { found_entry->second = value; } } }; std::vector<std::unique_ptr<bucket_type>> buckets; hash hasher; bucket_type& get_bucket(key const& key) const { std::size_t const bucket_index = hasher(key) % buckets.size(); return *buckets[bucket_index]; } template <typename key2, typename value2> friend std::ostream& operator<<(std::ostream& os, const thread_safe_hashmap<key2, value2>& map); public: thread_safe_hashmap(unsigned num_buckets = 19, hash const& hasher_ = hash()) : buckets(num_buckets), hasher(hasher_) { (unsigned = 0; < num_buckets; ++i) { buckets[i].reset(new bucket_type); } } thread_safe_hashmap(thread_safe_hashmap const& other) = delete; thread_safe_hashmap& operator=(thread_safe_hashmap const& other) = delete; void add_or_update_mapping(key const& key, value const& value) { get_bucket(key).add_or_update_mapping(key, value); } }; template <typename first, typename second> std::ostream& operator<<(std::ostream& os, const std::pair<first, second>& p) { os << p.first << ' ' << p.second << '\n'; return os; } template <typename key, typename value> std::ostream& operator<<(std::ostream& os, const thread_safe_hashmap<key, value>& map) { (unsigned = 0; < map.buckets.size(); ++i) { (const auto el : map.buckets[i]->data) os << el << ' '; os << '\n'; } return os; } int main() { thread_safe_hashmap<std::string, std::string> map; map.add_or_update_mapping("key1", "value1"); // problematic line std::cout << map; }
the marked line causing problems on both gcc , clang:
clang++ -wall -std=c++14 main2.cpp -lboost_system -o main main2.cpp:24:14: error: no viable conversion returned value of type 'std::_list_const_iterator<std::pair<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> > >' function return type 'bucket_iterator' (aka '_list_iterator<std::pair<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> > >') return std::find_if(data.begin(), data.end(), ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ main2.cpp:32:37: note: in instantiation of member function 'thread_safe_hashmap<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char>, std::hash<string> >::bucket_type::find_entry_for' requested here bucket_iterator found_entry = find_entry_for(key); ^ main2.cpp:71:21: note: in instantiation of member function 'thread_safe_hashmap<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char>, std::hash<string> >::bucket_type::add_or_update_mapping' requested here get_bucket(key).add_or_update_mapping(key, value); ^ main2.cpp:98:7: note: in instantiation of member function 'thread_safe_hashmap<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char>, std::hash<string> >::add_or_update_mapping' requested here map.add_or_update_mapping("key1", "value1"); ^ /usr/bin/../lib/gcc/x86_64-linux-gnu/5.3.1/../../../../include/c++/5.3.1/bits/stl_list.h:125:12: note: candidate constructor (the implicit copy constructor) not viable: no known conversion 'std::_list_const_iterator<std::pair<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> > >' 'const std::_list_iterator<std::pair<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> > > &' 1st argument struct _list_iterator ^ /usr/bin/../lib/gcc/x86_64-linux-gnu/5.3.1/../../../../include/c++/5.3.1/bits/stl_list.h:125:12: note: candidate constructor (the implicit move constructor) not viable: no known conversion 'std::_list_const_iterator<std::pair<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> > >' 'std::_list_iterator<std::pair<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> > > &&' 1st argument 1 error generated.
what missing here?
this expected behavior. in find_entry_for
you're trying return const_iterator
, doesn't match return type iterator
.
find_entry_for
const member function, data.begin()
, data
const std::list<bucket_value>
, begin()
called on return const_iterator
. , std::find_if
return same type type of parameter iterator, i.e. const_iterator
, not implicitly converted return type of find_entry_for
, i.e. bucket_iterator
(std::list::iterator
).
because returned iterator might used change value points to,
change
find_entry_for
non-const member function. (or add new overloading function, change original const member function's return typeconst_iterator
.)try convert
const_iterator
iterator
before returns.
Comments
Post a Comment