I am trying to convert my range (pair of iterators) to iterator_range so that I can take advantage of all the views and actions. I am able to convert my range to boost::iterator_range, but am getting a compilation failure when converting to range::v3. Here is a minimal example:
struct MyRange
{
struct iterator_t : std::iterator<std::input_iterator_tag, int>
{
friend bool operator==(const iterator_t& lhs, const iterator_t& rhs);
friend bool operator!=(const iterator_t& lhs, const iterator_t& rhs);
};
iterator_t begin() { return iterator_t{}; };
iterator_t end() { return iterator_t{}; };
};
int main(int argc, char *argv[])
{
auto my_range = MyRange{};
auto boost_range = boost::make_iterator_range(my_range.begin(), my_range.end()); // works
auto v3_range = ranges::v3::make_iterator_range(my_range.begin(), my_range.end()); // doesn't compile
}
It looks like I need to do something to satisfy the Sentinel concept of the iterator_range, but I haven't been able to figure out what. Any help is appreciated!
Edit: I am compiling with gcc54 -std=c++14. range v3/c++ compilations errors are kind of long, but here is a snippet:
range-v3/include/range/v3/iterator_range.hpp:171:17: note: in expansion of macro 'CONCEPT_REQUIRES_'
CONCEPT_REQUIRES_(Sentinel<S, I>())>
^
range-v3/include/range/v3/utility/concepts.hpp:669:15: note: invalid template non-type parameter
>::type = 0 \
^
range-v3/include/range/v3/iterator_range.hpp:171:17: note: in expansion of macro 'CONCEPT_REQUIRES_'
CONCEPT_REQUIRES_(Sentinel<S, I>())>
Your iterator is not an iterator. It's doesn't have dereference, pre- or post-increment.
auto my_range = MyRange{};
auto i = my_range.begin();
*i;
++i;
i++;
causes:
prog.cc: In function 'int main()':
prog.cc:20:5: error: no match for 'operator*' (operand type is 'MyRange::iterator_t')
*i;
^~
prog.cc:21:5: error: no match for 'operator++' (operand type is 'MyRange::iterator_t')
++i;
^~~
prog.cc:22:6: error: no 'operator++(int)' declared for postfix '++' [-fpermissive]
i++;
~^~
Related
Why doesn't std::ranges::common_view compile in the code below?
#include <ranges>
#include <vector>
#include <algorithm>
template <class T>
struct IteratorSentinel {};
template <class T>
class Iterator
{
public:
using iterator_category = std::input_iterator_tag;
using value_type = T;
using difference_type = std::ptrdiff_t;
using pointer = value_type*;
using reference = value_type&;
Iterator() = default;
Iterator(const Iterator&) = delete;
Iterator& operator = (const Iterator&) = delete;
Iterator(Iterator&& other) = default;
Iterator& operator = (Iterator&& other) = default;
T* operator-> () { return cur(); }
T& operator* () { return *cur(); }
T& operator* () const { return *cur(); };
bool operator== (const IteratorSentinel<T>&) const noexcept;
Iterator& operator++ ();
void operator++ (int);
private:
T* cur() const
{
return pCur;
}
T* pCur = nullptr;
};
static_assert(std::input_iterator<Iterator<int>>);
template <class T>
auto make_range()
{
return std::ranges::subrange(Iterator<T>(), IteratorSentinel<T>{});
}
int main()
{
auto r = make_range<int>();
auto cr = std::ranges::common_view{ r };
std::vector<int> v;
std::copy(cr.begin(), cr.end(), std::back_inserter(v));
return 0;
}
Can't figure out what template parameter does it require.
MSVC2022 error (/std:c++latest):
error C2641: cannot deduce template arguments for 'std::ranges::common_view'
error C2893: Failed to specialize function template 'std::ranges::common_view<_Vw> std::ranges::common_view(_Vw) noexcept(<expr>)'
GCC12 errors:
prog.cc: In function 'int main()':
prog.cc:67:43: error: class template argument deduction failed:
67 | auto cr = std::ranges::common_view{ r };
| ^
prog.cc:67:43: error: no matching function for call to 'common_view(std::ranges::subrange<Iterator<int>, IteratorSentinel<int>, std::ranges::subrange_kind::unsized>&)'
In file included from prog.cc:1:
/opt/wandbox/gcc-12.1.0/include/c++/12.1.0/ranges:3724:7: note: candidate: 'template<class _Vp> common_view(_Vp)-> std::ranges::common_view<_Vp>'
3724 | common_view(_Vp __r)
| ^~~~~~~~~~~
Your range is built out of an iterator/sentinel pair. The definition of a common range is a range where the sentinel type is an iterator. So the range itself is not a common range.
common_view can generate a common range from a non-common range. Which means that it will have to create two iterators. And since it starts the process with only one iterator, that means that, at some point, it must copy that iterator (thus creating two usable iterators).
Which it can't do because your iterator is non-copyable. Which is why common_view has an explicit requirement that the iterator is copyable.
Forward_iterator compiles fine!
#include <concepts>
#include <iterator>
// #include <iterator_concept>
using namespace std;
template<typename T>
// struct my_iterator : std::forward_iterator_tag{
struct my_iterator : std::bidirectional_iterator_tag {
T& operator*()const{
return *pointer;
}
my_iterator& operator++(){
++pointer;
return *this;
}
my_iterator operator++(int){
auto copy = *this;
++pointer;
return copy;
}
// my_iterator& operator--(){
// --pointer;
// return *this;
// }
// my_iterator operator--(int){
// auto copy = *this;
// --pointer;
// return copy;
// }
using difference_type = ptrdiff_t;
using value_type = T;
// auto operator<=>(const my_iterator&) const = default;
bool operator==(const my_iterator& other)const{
return pointer == other.pointer;
}
bool operator!=(const my_iterator& other)const{
return pointer != other.pointer;
}
private:
T*pointer;
};
// template<class T> constexpr bool always_false = false;
// static_assert(always_false<std::iter_reference_t<my_iterator<int>>>, "asd");
// typedef typename std::iter_reference_t<my_iterator<int>>::something_made_up X;
// static_assert(std::weakly_incrementable<my_iterator<int>>);
// static_assert(std::equality_comparable<my_iterator<int>>);
static_assert(std::forward_iterator<my_iterator<int>>);
// static_assert(std::bidirectional_iterator<my_iterator<int>>);
int main()
{
my_iterator<int> i1;
}
live snippet godbolt
but bidirectional does not. I tried g++ v10 and clang++ v11. Both give nearly the same compile time error.
#include <concepts>
#include <iterator>
using namespace std;
template<typename T>
// struct my_iterator : std::forward_iterator_tag{
struct my_iterator : std::bidirectional_iterator_tag {
T& operator*()const{
return *pointer;
}
my_iterator& operator++(){
++pointer;
return *this;
}
my_iterator operator++(int){
auto copy = *this;
++pointer;
return copy;
}
my_iterator& operator--(){
--pointer;
return *this;
}
my_iterator operator--(int){
auto copy = *this;
--pointer;
return copy;
}
using difference_type = ptrdiff_t;
using value_type = T;
// auto operator<=>(const my_iterator&) const = default; // Why this does not work
bool operator==(const my_iterator& other)const{
return pointer == other.pointer;
}
bool operator!=(const my_iterator& other)const{
return pointer != other.pointer;
}
private:
T*pointer;
};
// template<class T> constexpr bool always_false = false;
// static_assert(always_false<std::iter_reference_t<my_iterator<int>>>, "asd");
// typedef typename std::iter_reference_t<my_iterator<int>>::something_made_up X;
// static_assert(std::weakly_incrementable<my_iterator<int>>);
// static_assert(std::equality_comparable<my_iterator<int>>);
static_assert(std::forward_iterator<my_iterator<int>>);
// static_assert(std::bidirectional_iterator<my_iterator<int>>);
int main()
{
my_iterator<int> i1;
}
live
In file included from <source>:2:
In file included from /opt/compiler-explorer/gcc-10.2.0/lib/gcc/x86_64-linux-gnu/10.2.0/../../../../include/c++/10.2.0/iterator:61:
In file included from /opt/compiler-explorer/gcc-10.2.0/lib/gcc/x86_64-linux-gnu/10.2.0/../../../../include/c++/10.2.0/bits/stl_iterator_base_types.h:71:
/opt/compiler-explorer/gcc-10.2.0/lib/gcc/x86_64-linux-gnu/10.2.0/../../../../include/c++/10.2.0/bits/iterator_concepts.h:409:52: error: ambiguous partial specializations of '__cat<my_iterator<int>>'
using iterator_category = typename __detail::__cat<_Iterator>::type;
^
/opt/compiler-explorer/gcc-10.2.0/lib/gcc/x86_64-linux-gnu/10.2.0/../../../../include/c++/10.2.0/bits/stl_iterator_base_types.h:178:14: note: in instantiation of template class 'std::__iterator_traits<my_iterator<int>, void>' requested here
: public __iterator_traits<_Iterator> { };
^
/opt/compiler-explorer/gcc-10.2.0/lib/gcc/x86_64-linux-gnu/10.2.0/../../../../include/c++/10.2.0/bits/iterator_concepts.h:182:71: note: in instantiation of template class 'std::iterator_traits<my_iterator<int>>' requested here
= __is_base_of(__iterator_traits<_Iter, void>, iterator_traits<_Iter>);
^
/opt/compiler-explorer/gcc-10.2.0/lib/gcc/x86_64-linux-gnu/10.2.0/../../../../include/c++/10.2.0/bits/iterator_concepts.h:182:4: note: while substituting template arguments into constraint expression here
= __is_base_of(__iterator_traits<_Iter, void>, iterator_traits<_Iter>);
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/opt/compiler-explorer/gcc-10.2.0/lib/gcc/x86_64-linux-gnu/10.2.0/../../../../include/c++/10.2.0/bits/iterator_concepts.h:189:16: note: while checking the satisfaction of concept '__primary_traits_iter<my_iterator<int>>' requested here
requires __primary_traits_iter<_Iter>
^~~~~~~~~~~~~~~~~~~~~~~~~~~~
/opt/compiler-explorer/gcc-10.2.0/lib/gcc/x86_64-linux-gnu/10.2.0/../../../../include/c++/10.2.0/bits/iterator_concepts.h:189:16: note: while substituting template arguments into constraint expression here
requires __primary_traits_iter<_Iter>
^~~~~~~~~~~~~~~~~~~~~~~~~~~~
/opt/compiler-explorer/gcc-10.2.0/lib/gcc/x86_64-linux-gnu/10.2.0/../../../../include/c++/10.2.0/bits/iterator_concepts.h:195:7: note: (skipping 10 contexts in backtrace; use -ftemplate-backtrace-limit=0 to see all)
using __iter_traits = typename __iter_traits_impl<_Iter, _Tp>::type;
^
/opt/compiler-explorer/gcc-10.2.0/lib/gcc/x86_64-linux-gnu/10.2.0/../../../../include/c++/10.2.0/bits/iterator_concepts.h:564:30: note: while checking the satisfaction of concept 'input_or_output_iterator<my_iterator<int>>' requested here
concept input_iterator = input_or_output_iterator<_Iter>
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/opt/compiler-explorer/gcc-10.2.0/lib/gcc/x86_64-linux-gnu/10.2.0/../../../../include/c++/10.2.0/bits/iterator_concepts.h:564:30: note: while substituting template arguments into constraint expression here
concept input_iterator = input_or_output_iterator<_Iter>
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/opt/compiler-explorer/gcc-10.2.0/lib/gcc/x86_64-linux-gnu/10.2.0/../../../../include/c++/10.2.0/bits/iterator_concepts.h:575:32: note: while checking the satisfaction of concept 'input_iterator<my_iterator<int>>' requested here
concept forward_iterator = input_iterator<_Iter>
^~~~~~~~~~~~~~~~~~~~~
/opt/compiler-explorer/gcc-10.2.0/lib/gcc/x86_64-linux-gnu/10.2.0/../../../../include/c++/10.2.0/bits/iterator_concepts.h:575:32: note: while substituting template arguments into constraint expression here
concept forward_iterator = input_iterator<_Iter>
^~~~~~~~~~~~~~~~~~~~~
<source>:52:15: note: while checking the satisfaction of concept 'forward_iterator<my_iterator<int>>' requested here
static_assert(std::forward_iterator<my_iterator<int>>);
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/opt/compiler-explorer/gcc-10.2.0/lib/gcc/x86_64-linux-gnu/10.2.0/../../../../include/c++/10.2.0/bits/iterator_concepts.h:369:14: note: partial specialization matches [with _Iter = my_iterator<int>]
struct __cat<_Iter>
^
/opt/compiler-explorer/gcc-10.2.0/lib/gcc/x86_64-linux-gnu/10.2.0/../../../../include/c++/10.2.0/bits/iterator_concepts.h:375:14: note: partial specialization matches [with _Iter = my_iterator<int>]
struct __cat<_Iter>
^
<source>:52:1: error: static_assert failed
static_assert(std::forward_iterator<my_iterator<int>>);
^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
<source>:52:20: note: because 'my_iterator<int>' does not satisfy 'forward_iterator'
static_assert(std::forward_iterator<my_iterator<int>>);
^
/opt/compiler-explorer/gcc-10.2.0/lib/gcc/x86_64-linux-gnu/10.2.0/../../../../include/c++/10.2.0/bits/iterator_concepts.h:575:32: note: because 'my_iterator<int>' does not satisfy 'input_iterator'
concept forward_iterator = input_iterator<_Iter>
^
/opt/compiler-explorer/gcc-10.2.0/lib/gcc/x86_64-linux-gnu/10.2.0/../../../../include/c++/10.2.0/bits/iterator_concepts.h:564:30: note: because 'my_iterator<int>' does not satisfy 'input_or_output_iterator'
concept input_iterator = input_or_output_iterator<_Iter>
^
/opt/compiler-explorer/gcc-10.2.0/lib/gcc/x86_64-linux-gnu/10.2.0/../../../../include/c++/10.2.0/bits/iterator_concepts.h:544:5: note: because 'my_iterator<int>' does not satisfy 'weakly_incrementable'
&& weakly_incrementable<_Iter>;
^
/opt/compiler-explorer/gcc-10.2.0/lib/gcc/x86_64-linux-gnu/10.2.0/../../../../include/c++/10.2.0/bits/iterator_concepts.h:198:7: note: because 'typename iter_difference_t<_Iter>' would be invalid: no type named 'difference_type' in 'std::iterator_traits<my_iterator<int>>'
using __iter_diff_t = typename
^
2 errors generated.
Compiler returned: 1
x86-64 clang 11.0.0
1
More questions:
Why auto operator<=>(const my_iterator&) const = default; does not provide == and !=?
May be it does but static_assert(std::forward_iterator<my_iterator<int>>); want operator== to be explicit.
Is there a way to explicitly say this struct should meet the requirements and constraints of the concept like
template<typename T>
struct my_iterator implements forward_iterator {};
Currently I need to check it with static_assert(std::forward_iterator<my_iterator<int>>);.
This:
struct my_iterator : std::bidirectional_iterator_tag {
is not how you indicate the iterator category for an iterator. You don't inherit from a tag type, you have it as a member type alias.
Like so:
struct iterator {
using iterator_category = std::bidirectional_iterator_tag;
};
Although this shouldn't actually be necessary anyway. Even without this tag (and definitely without inheritance), this iterator should count as a bidirectional iterator since you satisfy the other requirements. It's actually a libstdc++ bug that it doesn't compile at that point.
Why auto operator<=>(const my_iterator&) const = default; does not provide == and !=?
It does. It's just that you were inheriting from a type (the iterator tag) that was not comparable, so the defaulted comparisons were defined as deleted.
Is there a way to explicitly say this struct should meet the requirements and constraints of the concept
There is not.
I am trying to fix some library code where a boiled-down minimal version looks like this:
#include <iostream>
template <typename RangeT>
struct formatter {
constexpr void format(const RangeT& values) {
for (auto it = values.begin(), end = values.end(); it != end; ++it) {
std::cout << it << "\n";
}
}
};
template <typename RangeT, typename Formatter>
struct type_erased {
static void format(const void* arg) {
Formatter f;
f.format(*static_cast<const RangeT*>(arg));
}
};
struct view {
int count_;
constexpr View(int count) : count_(count) {}
constexpr int
begin() { return 0; }
constexpr int
end() { return -1; }
};
int
main()
{
View view(5);
void* ptr = static_cast<void*>(&view);
type_erased<View, formatter<View>>::format(ptr);
}
The above code does not compile in GCC since:
../src/view.cpp: In instantiation of ‘constexpr void formatter<RangeT>::format(const RangeT&) [with RangeT = View]’:
../src/view.cpp:21:9: required from ‘static void type_erased<RangeT, Formatter>::format(const void*) [with RangeT = View; Formatter = formatter<View>]’
../src/view.cpp:43:41: required from here
../src/view.cpp:11:15: error: passing ‘const View’ as ‘this’ argument discards qualifiers [-fpermissive]
11 | for (auto it = values.begin(), end = values.end(); it != end; ++it) {
| ^~
../src/view.cpp:31:5: note: in call to ‘constexpr int View::begin()’
31 | begin() { return 0; }
| ^~~~~
../src/view.cpp:11:36: error: passing ‘const View’ as ‘this’ argument discards qualifiers [-fpermissive]
11 | for (auto it = values.begin(), end = values.end(); it != end; ++it) {
| ^~~
../src/view.cpp:34:5: note: in call to ‘constexpr int View::end()’
34 | end() { return -1; }
What are the rules regarding this in constexpr member function? Is it subject to the rules specified for function parameters or are there special constraints?
How would I go about fixing this error? If it would only be the formatter struct I would use RangeT&& and std::move since views are by definition copyable in O(1) as far as I know. I don't know how to do that with the type erasure step in the mix though...
Thanks in advance,
Richard
I don't think this has anything to do with constexpr.
You have a reference to const RangeT, and you're trying to invoke non-const member functions on it (begin() and end()).
Provide const overloads (and/or cbegin()/cend() variants) if you want to permit that.
In your code as begin and end are not const functions the this pointer can't point to a const object without "discarding qualifiers".
By making the functions const then the this pointer can point to a const object.
https://en.cppreference.com/w/cpp/language/member_functions#const-.2C_volatile-.2C_and_ref-qualified_member_functions
https://en.cppreference.com/w/cpp/language/this
https://godbolt.org/z/3_wKh9
I want to use Boost phoenix member function operator for the class function that has overloads, like here.
The following example fails:
#include <boost/phoenix/phoenix.hpp>
#include <boost/phoenix/operator.hpp>
using namespace std;
using namespace boost::phoenix::placeholders;
struct A
{
int m_id = 1;
int func() const { return 1; }
void func(int id) { m_id = id; }
};
int main()
{
A *a = new A;
auto retVal = (arg1->*&A::func)()(a);
return 0;
}
With error:
In function 'int main()': 17:21: error: no match for 'operator->*'
(operand types are 'const type {aka const
boost::phoenix::actor<boost::proto::exprns_::basic_expr<boost::proto::tagns_::
tag::terminal, boost::proto::argsns_::term<boost::phoenix::argument<1> >, 0l>
>}' and '<unresolved overloaded function type>') 17:21: note: candidate is: In
file included from /usr/include/boost/phoenix/operator/arithmetic.hpp:13:0,
from /usr/include/boost/phoenix/operator.hpp:13, from /usr/include/boost
/phoenix/phoenix.hpp:13, from 1: /usr/include/boost/proto/operators.hpp:295:9:
note: template<class Left, class Right> const typename
boost::proto::detail::enable_binary<boost::proto::domainns_::deduce_domain,
boost::proto::detail::not_a_grammar,
boost::mpl::or_<boost::proto::is_extension<Arg>,
boost::proto::is_extension<Right> >, boost::proto::tagns_::tag::mem_ptr, const
Left&, const Right&>::type boost::proto::exprns_::operator->*(Left&&,
Right&&) BOOST_PROTO_DEFINE_OPERATORS(is_extension, deduce_domain) ^
/usr/include/boost/proto/operators.hpp:295:9: note: template argument
deduction/substitution failed: 17:28: note: couldn't deduce template parameter
'Right'
However, if I comment the line void func(int id) { m_id = id; } out, it works as expected.
How can I tell which of the overloads to use?
Handling (member) function pointers to overload sets is always a pain. You need to cast the address to a pointer that has the exact signature of the desired overload. In your case, for selection int A::func():
auto retVal = (arg1->*static_cast<int (A::*)() const>(&A::func))()(a);
or a bit more readable, but basically the same:
const auto memFctPtr = static_cast<int (A::*)() const>(&A::func);
auto retVal = (arg1->*memFctPtr)()(a);
Inspired by Antony's Williams "C++ Concurrency in Action" I wanted to take a closed look at his thread safe hash map. I copied its code and added some output operators and this is what I came up 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_)
{
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;
}
The marked line is causing problems on both gcc and 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.
melpon's online demo
What am I missing here?
This is the expected behavior. In find_entry_for you're trying to return const_iterator, which doesn't match the return type iterator.
find_entry_for is const member function, for data.begin(), data will be const std::list<bucket_value>, begin() called on it will return const_iterator. And std::find_if will return the same type with the type of the parameter iterator, i.e. const_iterator, which could not be implicitly converted to the return type of find_entry_for, i.e. bucket_iterator (std::list::iterator).
Because the returned iterator might be used to change the value it points to, you could
Change find_entry_for to non-const member function. (Or add it as new overloading function, change the original const member function's return type to const_iterator.)
Try to convert const_iterator to iterator before returns.
bucket_iterator is defined the following way
typedef typename bucket_data::iterator bucket_iterator;
That is it is not a constant iterator.
However in member function 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; });
}
standard algorithm std::find_if uses the constant iterator because this member function is declared with qualifier const and there are used overloaded functions begin and end for the constant data member data.
So you need to define the constant iterator in the class and use it as the return type of the function.
For example
typedef typename bucket_data::const_iterator const_bucket_iterator;