Using std::swap_ranges with std::map - c++

I would like to swap parts of two maps using a standard algorithm, but somehow iterators on map do not seem to be swappable. I am surely missing something.
Example
#include<map>
#include<algorithm>
auto function(std::map<int,int> m1, std::map<int,int> m2)
{
auto first = m1.begin();
auto last = first;
std::advance(last, 3);
std::swap_ranges(first, last, m2.begin());
}
Error
See it on compiler explorer: https://godbolt.org/z/6bn1xYTTr
In file included from /opt/compiler-explorer/gcc-12.2.0/include/c++/12.2.0/bits/stl_tree.h:63,
from /opt/compiler-explorer/gcc-12.2.0/include/c++/12.2.0/map:60,
from <source>:1:
/opt/compiler-explorer/gcc-12.2.0/include/c++/12.2.0/bits/stl_algobase.h: In instantiation of 'void std::iter_swap(_ForwardIterator1, _ForwardIterator2) [with _ForwardIterator1 = _Rb_tree_iterator<pair<const int, int> >; _ForwardIterator2 = _Rb_tree_iterator<pair<const int, int> >]':
/opt/compiler-explorer/gcc-12.2.0/include/c++/12.2.0/bits/stl_algobase.h:212:16: required from '_ForwardIterator2 std::swap_ranges(_ForwardIterator1, _ForwardIterator1, _ForwardIterator2) [with _ForwardIterator1 = _Rb_tree_iterator<pair<const int, int> >; _ForwardIterator2 = _Rb_tree_iterator<pair<const int, int> >]'
<source>:9:21: required from here
/opt/compiler-explorer/gcc-12.2.0/include/c++/12.2.0/bits/stl_algobase.h:182:11: error: use of deleted function 'typename std::enable_if<(! std::__and_<std::__is_swappable<_T1>, std::__is_swappable<_T2> >::value)>::type std::swap(pair<_T1, _T2>&, pair<_T1, _T2>&) [with _T1 = const int; _T2 = int; typename enable_if<(! __and_<__is_swappable<_T1>, __is_swappable<_T2> >::value)>::type = void]'
182 | swap(*__a, *__b);
| ~~~~^~~~~~~~~~~~
In file included from /opt/compiler-explorer/gcc-12.2.0/include/c++/12.2.0/bits/stl_algobase.h:64:
/opt/compiler-explorer/gcc-12.2.0/include/c++/12.2.0/bits/stl_pair.h:715:5: note: declared here
715 | swap(pair<_T1, _T2>&, pair<_T1, _T2>&) = delete;
| ^~~~
Compiler returned: 1

std::map is implemented as some sort of binary search tree, and its structure depends on each item's key never changing. Thus the type returned by *m1.begin() is std::pair<const int, int>&. Note that the first int is const. You cannot modify it.
std::swap_ranges tries to swap each element of the first range with its corresponding element in the second range, but std::pair<const int, int>s can't be swapped due to the constness of their first element.

Related

passing const iterator as ‘this’ argument discards qualifiers while using vector::erase in a template

I am trying to remove the first value of a vector of template typenames. Using the erase() method in vector stl, I keep getting this error:
TTrie.inc:56:19: error: passing ‘const std::vector<char, std::allocator<char> >’ as ‘this’ argument discards qualifiers [-fpermissive]
56 | sequence.erase(it);
| ~~~~~~~~~~~~~~^~~~
In file included from /usr/include/c++/10/vector:67,
from TTrie.h:5,
from TTrieTest.cpp:1:
/usr/include/c++/10/bits/stl_vector.h:1430:7: note: in call to ‘std::vector<_Tp, _Alloc>::iterator std::vector<_Tp, _Alloc>::erase(std::vector<_Tp, _Alloc>::const_iterator) [with _Tp = char; _Alloc = std::allocator<char>; std::vector<_Tp, _Alloc>::iterator = std::vector<char, std::allocator<char> >::iterator; std::vector<_Tp, _Alloc>::const_iterator = std::vector<char, std::allocator<char> >::const_iterator]’
1430 | erase(const_iterator __position)
| ^~~~~
In file included from TTrie.h:115,
from TTrieTest.cpp:1:
TTrie.inc: In instantiation of ‘TTrie<DataType>& TTrie<DataType>::operator+=(const std::vector<DataType>&) [with DataType = std::__cxx11::basic_string<char>]’:
TTrieTest.cpp:93:10: required from here
TTrie.inc:56:19: error: passing ‘const std::vector<std::__cxx11::basic_string<char> >’ as ‘this’ argument discards qualifiers [-fpermissive]
56 | sequence.erase(it);
| ~~~~~~~~~~~~~~^~~~
In file included from /usr/include/c++/10/vector:67,
from TTrie.h:5,
from TTrieTest.cpp:1:
/usr/include/c++/10/bits/stl_vector.h:1430:7: note: in call to ‘std::vector<_Tp, _Alloc>::iterator std::vector<_Tp, _Alloc>::erase(std::vector<_Tp, _Alloc>::const_iterator) [with _Tp = std::__cxx11::basic_string<char>; _Alloc = std::allocator<std::__cxx11::basic_string<char> >; std::vector<_Tp, _Alloc>::iterator = std::vector<std::__cxx11::basic_string<char> >::iterator; std::vector<_Tp, _Alloc>::const_iterator = std::vector<std::__cxx11::basic_string<char> >::const_iterator]’
1430 | erase(const_iterator __position)
| ^~~~~
In file included from TTrie.h:115,
from TTrieTest.cpp:1:
Is it having trouble because sequence should be const? Am I declaring the iterator wrong somehow? Here is my code. Please let me know If you have any questions:
template<typename DataType>
TTrie<DataType>& TTrie<DataType>::operator+=(const std::vector<DataType>& sequence) {
const DataType c = sequence[0];
const TTrie<DataType>* child = getChild(c); //Returns a pointer to a child node or a nullptr
if (!child) {
TTrie<DataType>* n = new TTrie<DataType>(c);
edgeMap[c] = n;
}
if(sequence.size() > 1) {
typename std::vector<DataType>::const_iterator it;
it = sequence.cbegin(); //First value of sequence
sequence.erase(it);
*edgeMap[c] += sequence;
}
return *this;
}
Your sequence parameter is a reference to a const std::vector<DataType> object. But std::vector::erase() is not qualified as being a const method, as it modifies the content of the vector, so it cannot be called on a const object. That is what the error message is trying to tell you - that erase() is being called on a const object.

Conversion Error when passing arguments to lambda comparator

I have a sorted vector of structures and I am trying to find the index of element that has the queried value in its member attribute. For this I am trying to use lower_bound, but I am having problems with the comparator lambda function. Here is a simplified version of my code:
#include <iostream>
#include <vector>
#include <algorithm>
struct Student
{
int id;
};
std::vector<Student> Students;
int main()
{
Student Ann = {1};
Student Bob = {3};
Student Alice = {4};
Students = {Ann, Bob, Alice};
int id_query = 3;
auto index_ptr = std::lower_bound(Students.begin(), Students.end(), id_query, [](const int a, const Student s) -> bool {return a < s.id;});
}
g++ with std=17 gives me the following
Starting build...
/bin/g++ -g /home/aram/dev/cpp/coverages/stack_overflow.cpp -std=c++17 -o /home/aram/dev/cpp/coverages/stack_overflow
In file included from /usr/include/c++/9/bits/stl_algobase.h:71,
from /usr/include/c++/9/bits/char_traits.h:39,
from /usr/include/c++/9/ios:40,
from /usr/include/c++/9/ostream:38,
from /usr/include/c++/9/iostream:39,
from /home/aram/dev/cpp/coverages/stack_overflow.cpp:1:
/usr/include/c++/9/bits/predefined_ops.h: In instantiation of ‘bool __gnu_cxx::__ops::_Iter_comp_val<_Compare>::operator()(_Iterator, _Value&) [with _Iterator = __gnu_cxx::__normal_iterator<Student*, std::vector<Student> >; _Value = const int; _Compare = main()::<lambda(int, Student)>]’:
/usr/include/c++/9/bits/stl_algobase.h:979:14: required from ‘_ForwardIterator std::__lower_bound(_ForwardIterator, _ForwardIterator, const _Tp&, _Compare) [with _ForwardIterator = __gnu_cxx::__normal_iterator<Student*, std::vector<Student> >; _Tp = int; _Compare = __gnu_cxx::__ops::_Iter_comp_val<main()::<lambda(int, Student)> >]’
/usr/include/c++/9/bits/stl_algo.h:2032:32: required from ‘_FIter std::lower_bound(_FIter, _FIter, const _Tp&, _Compare) [with _FIter = __gnu_cxx::__normal_iterator<Student*, std::vector<Student> >; _Tp = int; _Compare = main()::<lambda(int, Student)>]’
/home/aram/dev/cpp/coverages/stack_overflow.cpp:21:142: required from here
/usr/include/c++/9/bits/predefined_ops.h:177:11: error: no match for call to ‘(main()::<lambda(int, Student)>) (Student&, const int&)’
177 | { return bool(_M_comp(*__it, __val)); }
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~
/usr/include/c++/9/bits/predefined_ops.h:177:11: note: candidate: ‘bool (*)(int, Student)’ <conversion>
/usr/include/c++/9/bits/predefined_ops.h:177:11: note: candidate expects 3 arguments, 3 provided
/home/aram/dev/cpp/coverages/stack_overflow.cpp:21:83: note: candidate: ‘main()::<lambda(int, Student)>’
21 | auto index_ptr = std::lower_bound(Students.begin(), Students.end(), id_query, [](const int a, const Student s) -> bool {return a < s.id;});
| ^
/home/aram/dev/cpp/coverages/stack_overflow.cpp:21:83: note: no known conversion for argument 1 from ‘Student’ to ‘int’
Build finished with error(s).
The terminal process failed to launch (exit code: -1).
The comparator of std::lower_bound is supposed to take the object dereferenced from the iterator, i.e. the element as the 1st parameter, the value to be compared as the 2nd parameter.
The type Type1 must be such that an object of type ForwardIt can be dereferenced and then implicitly converted to Type1. The type Type2 must be such that an object of type T can be implicitly converted to Type2.​
You need to change the order of the parameters, e.g.
auto index_ptr = std::lower_bound(Students.begin(), Students.end(), id_query, [](const Student s, const int a) -> bool {return s.id < a;});
LIVE

Usage of multimap with next_permutation c++

i am just trying to implement Knapsack Problem in a Naive way to stress test my original solution.
MY CODE
double StressTest(multimap<int, int> ValWt, int KnapscakWeight)
{
vector<double> TotalValue;
double Temp_KnapsackWeight = 0.0;
double Value = 0.0;
multimap<int, int>::iterator itr1;// = ValWt.begin();
do
{
itr1 = ValWt.begin();
Temp_KnapsackWeight = KnapscakWeight;
while( (Temp_KnapsackWeight > 0) && (itr1 != ValWt.end()) )
{
if(itr1->second > Temp_KnapsackWeight)
{
Value += ( (Temp_KnapsackWeight/itr1->second) * itr1->first );
Temp_KnapsackWeight = 0;
}
else
{
Temp_KnapsackWeight -= itr1->second;
Value += itr1->first;
}
itr1++;
}
TotalValue.push_back(Value);
Value = 0.0;
}while( next_permutation(ValWt.begin(), ValWt.end()) );
return *max_element(TotalValue.begin(), TotalValue.end());
}
ERROR
In file included from /usr/include/c++/7/bits/char_traits.h:39:0,
from /usr/include/c++/7/ios:40,
from /usr/include/c++/7/ostream:38,
from /usr/include/c++/7/iostream:39,
from 2_max_val_of_loot.cpp:1:
/usr/include/c++/7/bits/stl_algobase.h: In instantiation of ‘void std::iter_swap(_ForwardIterator1, _ForwardIterator2) [with _ForwardIterator1 = std::_Rb_tree_iterator<std::pair<const int, int> >; _ForwardIterator2 = std::_Rb_tree_iterator<std::pair<const int, int> >]’:
/usr/include/c++/7/bits/stl_algo.h:2926:22: required from ‘bool std::__next_permutation(_BidirectionalIterator, _BidirectionalIterator, _Compare) [with _BidirectionalIterator = std::_Rb_tree_iterator<std::pair<const int, int> >; _Compare = __gnu_cxx::__ops::_Iter_less_iter]’
/usr/include/c++/7/bits/stl_algo.h:2966:2: required from ‘bool std::next_permutation(_BIter, _BIter) [with _BIter = std::_Rb_tree_iterator<std::pair<const int, int> >]’
2_max_val_of_loot.cpp:39:53: required from here
/usr/include/c++/7/bits/stl_algobase.h:148:11: error: use of deleted function ‘typename std::enable_if<(! std::__and_<std::__is_swappable<_T1>, std::__is_swappable<_T2> >::value)>::type std::swap(std::pair<_T1, _T2>&, std::pair<_T1, _T2>&) [with _T1 = const int; _T2 = int; typename std::enable_if<(! std::__and_<std::__is_swappable<_T1>, std::__is_swappable<_T2> >::value)>::type = void]’
swap(*__a, *__b);
~~~~^~~~~~~~~~~~
In file included from /usr/include/c++/7/bits/stl_algobase.h:64:0,
from /usr/include/c++/7/bits/char_traits.h:39,
from /usr/include/c++/7/ios:40,
from /usr/include/c++/7/ostream:38,
from /usr/include/c++/7/iostream:39,
from 2_max_val_of_loot.cpp:1:
/usr/include/c++/7/bits/stl_pair.h:503:5: note: declared here
swap(pair<_T1, _T2>&, pair<_T1, _T2>&) = delete;
MY OBSERVATION
next_permutation() is creating error, but why i don't understand why.
next_permutation() requires bidirectional iterator and multimap iterator is a bidirectional iterator.
I doubt as multimap are sorted always, that's why the error is shown ??
Please Help.
Thanking You.
You cannot use std::map or std::multimap (or unordered versions) as std::next_permutation requires:
-BidirIt must meet the requirements of ValueSwappable and LegacyBidirectionalIterator.
but std::multimap values are not swappable as key in the map is not mutable:
value_type std::pair<const Key, T>
(emphasis is mine)
Less formally order of elements in map is determined and cannot me changed. You have to use different container like std::vector to perform this operation.

How can I use std::rotate to rotate an array of pairs whose first member is const?

I am implementing a map, and I would like to use std::rotate on an array of pairs, of which the first member is const (so that the key cannot be changed when inserted in the map). It is equivalent to the code below which doesn't compile:
#include <utility>
#include <array>
#include <algorithm>
int main()
{
typedef std::pair<const int, int> map_entry;
std::array<map_entry, 3> a{ { {2, 0}, {1, 0}, {3, 0} } };
std::rotate(&a[0], &a[1], &a[3]);
}
Unfortunately, I cannot control the type of the pair ("value_type") which needs to be defined as follows be compatible with std::unordered_map:
template <class K, class T, class H, class P, class A>
class unordered_map
{
public:
typedef K key_type;
typedef std::pair<const K, T> value_type;
typedef T mapped_type;
Is there way for me to use std::rotate on such an array, maybe by removing the const somehow?
Here is the compile error:
$ g++ -std=c++11 xx.cxx
In file included from /usr/lib/gcc/i686-pc-cygwin/4.8.2/include/c++/utility:70:0,
from xx.cxx:1:
/usr/lib/gcc/i686-pc-cygwin/4.8.2/include/c++/bits/stl_pair.h: In instantiation of ‘std::pair<_T1, _T2>& std::pair<_T1, _T2>::operator=(std::pair<_T1 , _T2>&&) [with _T1 = const int; _T2 = int]’:
/usr/lib/gcc/i686-pc-cygwin/4.8.2/include/c++/bits/stl_algo.h:1610:22: required from ‘void std::__rotate(_RandomAccessIterator, _RandomAccessIterat or, _RandomAccessIterator, std::random_access_iterator_tag) [with _RandomAccessIterator = std::pair<const int, int>*]’
/usr/lib/gcc/i686-pc-cygwin/4.8.2/include/c++/bits/stl_algo.h:1686:59: required from ‘void std::rotate(_FIter, _FIter, _FIter) [with _FIter = std:: pair<const int, int>*]’
xx.cxx:9:36: required from here
/usr/lib/gcc/i686-pc-cygwin/4.8.2/include/c++/bits/stl_pair.h:170:8: error: assignment of read-only member ‘std::pair<const int, int>::first’
first = std::forward<first_type>(__p.first);
^
In file included from /usr/lib/gcc/i686-pc-cygwin/4.8.2/include/c++/bits/stl_pair.h:59:0,
from /usr/lib/gcc/i686-pc-cygwin/4.8.2/include/c++/utility:70,
from xx.cxx:1:
/usr/lib/gcc/i686-pc-cygwin/4.8.2/include/c++/bits/move.h: In instantiation of ‘void std::swap(_Tp&, _Tp&) [with _Tp = const int]’:
/usr/lib/gcc/i686-pc-cygwin/4.8.2/include/c++/bits/stl_pair.h:199:23: required from ‘void std::pair<_T1, _T2>::swap(std::pair<_T1, _T2>&) [with _T1 = const int; _T2 = int]’
/usr/lib/gcc/i686-pc-cygwin/4.8.2/include/c++/bits/stl_pair.h:256:7: required from ‘void std::swap(std::pair<_T1, _T2>&, std::pair<_T1, _T2>&) [wit h _T1 = const int; _T2 = int]’
/usr/lib/gcc/i686-pc-cygwin/4.8.2/include/c++/bits/stl_algobase.h:147:22: required from ‘void std::iter_swap(_ForwardIterator1, _ForwardIterator2) [with _ForwardIterator1 = std::pair<const int, int>*; _ForwardIterator2 = std::pair<const int, int>*]’
/usr/lib/gcc/i686-pc-cygwin/4.8.2/include/c++/bits/stl_algo.h:1616:28: required from ‘void std::__rotate(_RandomAccessIterator, _RandomAccessIterat or, _RandomAccessIterator, std::random_access_iterator_tag) [with _RandomAccessIterator = std::pair<const int, int>*]’
/usr/lib/gcc/i686-pc-cygwin/4.8.2/include/c++/bits/stl_algo.h:1686:59: required from ‘void std::rotate(_FIter, _FIter, _FIter) [with _FIter = std:: pair<const int, int>*]’
xx.cxx:9:36: required from here
/usr/lib/gcc/i686-pc-cygwin/4.8.2/include/c++/bits/move.h:176:11: error: assignment of read-only reference ‘__a’
__a = _GLIBCXX_MOVE(__b);
^
/usr/lib/gcc/i686-pc-cygwin/4.8.2/include/c++/bits/move.h:177:11: error: assignment of read-only reference ‘__b’
__b = _GLIBCXX_MOVE(__tmp);
^
Simple: don't use std::pair. Design a class that has the semantics that you need and use that. In particular, don't make the data members const. Instead, make them private and write accessors to enforce const-ness. int first() const;, int second() const; and int& second(); are a good start. But they really should be named key() and value(), or something else that matches your design better.
I found my solution. Internally, I store the pair without the const (mutable_value_type), but I still define value_type with the const and this is what is returned when you dereference an iterator for example.
template <class K, class T, class H, class P, class A>
class unordered_map
{
public:
typedef K key_type;
typedef std::pair<const K, T> value_type;
typedef std::pair<K, T> mutable_value_type;

C++ std::sort a vector of share_ptr<objects>

How can I sort a vector of shared_ptrs C++? I'm trying to sort a vector a share_ptrs of struct data object. And the comparator function is also defined.
struct data{
int number;
};
bool comparator(const std::shared_ptr<data> &a, const std::shared_ptr<data> &b) {
return a->number < b->number();
}
int main() {
std::vector<std::shared_ptr<data>> v;
std::sort(v.begin(), v.end(), comparator);
}
But I got compile error:
In file included from /usr/include/c++/4.8/algorithm:62:0,
from test.cpp:10:
/usr/include/c++/4.8/bits/stl_algo.h: In instantiation of ‘void std::__insertion_sort(_RandomAccessIterator, _RandomAccessIterator, _Compare) [with _RandomAccessIterator = __gnu_cxx::__normal_iterator<std::shared_ptr<data>*, std::vector<std::shared_ptr<data> > >; _Compare = bool (*)(const A&, const A&)]’:
/usr/include/c++/4.8/bits/stl_algo.h:2226:70: required from ‘void std::__final_insertion_sort(_RandomAccessIterator, _RandomAccessIterator, _Compare) [with _RandomAccessIterator = __gnu_cxx::__normal_iterator<std::shared_ptr<data>*, std::vector<std::shared_ptr<data> > >; _Compare = bool (*)(const A&, const A&)]’
/usr/include/c++/4.8/bits/stl_algo.h:5491:55: required from ‘void std::sort(_RAIter, _RAIter, _Compare) [with _RAIter = __gnu_cxx::__normal_iterator<std::shared_ptr<data>*, std::vector<std::shared_ptr<data> > >; _Compare = bool (*)(const A&, const A&)]’
test.cpp:110:45: required from here
/usr/include/c++/4.8/bits/stl_algo.h:2159:29: error: invalid initialization of reference of type ‘const A&’ from expression of type ‘std::shared_ptr<data>’
.....
return a->number < b->number();
Must be:
return a->number < b->number;
However, I wonder if this is your real code and which compiler you are using. You should get much clearer error messages, for example:
Visual C++ 2013:
error C2064: term does not evaluate to a function taking 0 arguments
GCC v4.8.3:
error: expression cannot be used as a function
return a->number < b->number();
^
P.S.: You should post your complete code with all #includes when asking such questions. In your case, <vector>, <algorithm> and <memory>.