Reputation: 355
I have written (partailly copied :) ) the following code: HigherOrderFunctions.h :
#ifndef HigherOrderFunctions_H
#define HigherOrderFunctions_H
#include <algorithm>
class HigherOrderFunctions {
public:
template<class Coll, class Func>
static Coll& filter(Coll& items, Func&& filterFunc);
private:
HigherOrderFunctions() {}
};
template < class Coll, class Func>
Coll& HigherOrderFunctions::filter(Coll& items, Func&& filterFunc) {
auto first = std::find_if_not(items.begin(), items.end(), filterFunc);
const auto last = items.end();
if (first != last) {
for(auto it = first; ++it != last; ) {
if (filterFunc(*it)) {
*first++ = std::move(*it);
}
}
}
items.erase(first, items.end());
return items;
}
#endif // HigherOrderFunctions_H
Now when I try to test the above code with the test function:
void HighOrderFunctionsTest::testFilter() {
vector<int> integers = {1, 2, 3, 4, 5, 6, 7};
HigherOrderFunctions::filter(integers, [](int elem) -> bool {
return (elem % 2) == 0;
});
const int ADULT_AGE = 18;
map<string, int> name_age_list = {{"sm", 10}, {"ak", 20}, {"al", 30}, {"am", 35}};
function<bool(const pair<string, int>&)> funct = [ADULT_AGE](const pair<string, int>& elem) -> bool {
return (elem.second > ADULT_AGE);
};
HigherOrderFunctions::filter(name_age_list, funct);
}
The part where I filter the vector compiles OK, but when I add the part with map I get the following compile error (using MSVS 2013):
HighOrderFunctionsTest.cpp
2>C:\winapp\MSVS2013PRO\VC\include\utility(175): error C2678: binary '=' : no operator found which takes a left-hand operand of type 'const std::string' (or there is no acceptable conversion)
2> C:\winapp\MSVS2013PRO\VC\include\xstring(1017): could be 'std::basic_string<char,std::char_traits<char>,std::allocator<char>> &std::basic_string<char,std::char_traits<char>,std::allocator<char>>::operator =(_Elem)'
2> with
2> [
2> _Elem=char
2> ]
2> C:\winapp\MSVS2013PRO\VC\include\xstring(1012): or 'std::basic_string<char,std::char_traits<char>,std::allocator<char>> &std::basic_string<char,std::char_traits<char>,std::allocator<char>>::operator =(const _Elem *)'
2> with
2> [
2> _Elem=char
2> ]
2> C:\winapp\MSVS2013PRO\VC\include\xstring(996): or 'std::basic_string<char,std::char_traits<char>,std::allocator<char>> &std::basic_string<char,std::char_traits<char>,std::allocator<char>>::operator =(const std::basic_string<char,std::char_traits<char>,std::allocator<char>> &)'
2> C:\winapp\MSVS2013PRO\VC\include\xstring(957): or 'std::basic_string<char,std::char_traits<char>,std::allocator<char>> &std::basic_string<char,std::char_traits<char>,std::allocator<char>>::operator =(std::initializer_list<_Elem>)'
2> with
2> [
2> _Elem=char
2> ]
2> C:\winapp\MSVS2013PRO\VC\include\xstring(901): or 'std::basic_string<char,std::char_traits<char>,std::allocator<char>> &std::basic_string<char,std::char_traits<char>,std::allocator<char>>::operator =(std::basic_string<char,std::char_traits<char>,std::allocator<char>> &&) throw()'
2> while trying to match the argument list '(const std::string, const std::string)'
2> C:\winapp\MSVS2013PRO\VC\include\utility(174) : while compiling class template member function 'std::pair<const _Kty,_Ty> &std::pair<const _Kty,_Ty>::operator =(std::pair<const _Kty,_Ty> &&)'
2> with
2> [
2> _Kty=std::string
2> , _Ty=int
2> ]
2> D:\tax\tax_win\tc\src\cpp\foundation\HigherOrderFunctions.h(219) : see reference to function template instantiation 'std::pair<const _Kty,_Ty> &std::pair<const _Kty,_Ty>::operator =(std::pair<const _Kty,_Ty> &&)' being compiled
2> with
2> [
2> _Kty=std::string
2> , _Ty=int
2> ]
2> ..\..\..\..\..\..\src\cpp\foundation\test\HighOrderFunctionsTest.cpp(33) : see reference to class template instantiation 'std::pair<const _Kty,_Ty>' being compiled
2> with
2> [
2> _Kty=std::string
2> , _Ty=int
2> ]
I have looked for similar errors and I found out that this could happen if my function where the code is called would be const, but it is not. Can you please help me with this problem?
Upvotes: 0
Views: 1386
Reputation: 37600
The problem is cause by *first++ = std::move(*it);
line. When container is a map
then stored items will be of type pair<const Key, Value>
. De-referencing iterator will yield a reference to such a type and any attempt to perform move assignment to it will fail because the value of Key
can not be changed.
I think the key issue with this code is that filter function is supposed to produce a new container with filtered values, not mutate supplied container. Currently implemented algorithm seems to be working similar to std::remove_if
.
Upvotes: 2