![](/img/trans.png)
[英]const_iterator and constness of const_iterator::value_type
[英]no viable conversion from returned value of type const_iterator to iterator
受Antony's Williams“行动中的C ++并发”的启发,我想密切关注他的线程安全哈希映射。 我复制了它的代码并添加了一些输出操作符,这就是我提出的:
#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_)
{
for (unsigned i = 0; i < 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)
{
for (unsigned i = 0; i < map.buckets.size(); ++i)
{
for (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;
}
标记的行导致gcc和clang都出现问题:
clang++ -Wall -std=c++14 main2.cpp -lboost_system -o main
main2.cpp:24:14: error: no viable conversion from returned value of type 'std::_List_const_iterator<std::pair<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> > >' to 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 from
'std::_List_const_iterator<std::pair<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> > >' to 'const std::_List_iterator<std::pair<std::__cxx11::basic_string<char>,
std::__cxx11::basic_string<char> > > &' for 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 from
'std::_List_const_iterator<std::pair<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> > >' to 'std::_List_iterator<std::pair<std::__cxx11::basic_string<char>,
std::__cxx11::basic_string<char> > > &&' for 1st argument
1 error generated.
我在这里错过了什么?
这是预期的行为。 在find_entry_for
您尝试返回const_iterator
,它与返回类型iterator
不匹配。
find_entry_for
是const成员函数,对于data.begin()
, data
将是const std::list<bucket_value>
,在它上面调用begin()
将返回const_iterator
。 并且std::find_if
将返回与参数迭代器类型相同的类型,即const_iterator
,它无法隐式转换为find_entry_for
的返回类型,即bucket_iterator
( std::list::iterator
)。
因为返回的迭代器可能用于更改它指向的值,所以可以
将find_entry_for
更改为非const成员函数。 (或者将其添加为新的重载函数,将原始const成员函数的返回类型更改为const_iterator
。)
尝试在返回之前将const_iterator
转换为iterator
。
bucket_iterator
的定义方式如下
typedef typename bucket_data::iterator bucket_iterator;
那就是它不是一个恒定的迭代器。
但是在成员函数find_entry_for
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; });
}
标准算法std::find_if
使用常量迭代器,因为此成员函数使用限定符const
声明,并且使用重载函数begin
和end
作为常量数据成员data
。
因此,您需要在类中定义常量迭代器,并将其用作函数的返回类型。
例如
typedef typename bucket_data::const_iterator const_bucket_iterator;
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.