c++ - no viable conversion from returned value of type const_iterator to iterator -


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. 

melpon's online demo

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,

  1. change find_entry_for non-const member function. (or add new overloading function, change original const member function's return type const_iterator.)

  2. try convert const_iterator iterator before returns.


Comments