moving elements in a vector is not working as expected - c++

I'm trying to move each element that has x value to the beginning of vector so that all the element that has x value is at the front of the vector, but it is not working , so can you tell me what I've done wrong, please?
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
template <typename Container, typename Arg>
void move_x(Container& c, Arg x)
{
typename Container::iterator it = find(c.begin(), c.end(), x);
if (it!=c.end()) {
c.insert(c.begin(), *it);
remove (it, c.end(), x);
}
}
int main()
{
int x=1;
vector <int> v{1,2,4,6,7,1,3,1,1,8,9};
move_x(v, x);
for(auto i:v)
cout<<v[i];
return 0;
}
and I'm getting this output when I run it
411613848811

Once you insert into the container, the iterator is no longer valid
c.insert(c.begin(), *it); // This invalidates 'it'
remove (it, c.end(), x); // oops! trying to use invalid iterator
Using std::rotate provides better alternative, which doesn't invalidate the iterators:
template <typename Container, typename Arg>
void move_x(Container& c, Arg x)
{
typedef typename Container::iterator It;
It write_it = c.begin(), read_it = c.begin();
for (;;) {
It found_it = find(read_it, c.end(), x);
if (found_it==c.end()) break;
read_it = found_it;
++read_it;
std::rotate(write_it,found_it,read_it);
++write_it;
}
}
As long as you are dealing with simple items like ints, this is a good approach:
template <typename Container, typename Arg>
void move_x(Container& c, Arg x)
{
typename Container::reverse_iterator it = std::remove(c.rbegin(),c.rend(),x);
for (;it!=c.rend();++it) {
*it = x;
}
}

This is a fixed implementation, of what you had in your code:
template <typename Container, typename Arg>
void move_x(Container& c, Arg x)
{
typename Container::iterator it = find(c.begin(), c.end(), x);
if (it!=c.end()) {
c.erase(it);
c.insert(c.end(), x);
}
}
One issue with your implementation is that insert anywhere but the end can cause a reallocation and regardless will invalidate anything after the inserted position. So by definition since you are inserting at the beginning it will not be valid.
The second issue is with cout<<v[i]; it should actually be cout<<i;.
A nicer implementation that uses reverse iterators and moves all xs. This one erases as it goes and keeps a count and then does count inserts when done. Using erase with reverse iterators is a little tricky:
template <typename Container, typename Arg>
void move_all_x(Container& c, Arg x)
{
unsigned int count = 0 ;
for( typename Container::reverse_iterator it = c.rbegin() ; it != c.rend(); )
{
if( *it == x )
{
c.erase(--(it++).base() ) ;
++count ;
}
else
{
++it ;
}
}
for( unsigned int i = 0; i < count; ++i )
{
c.insert(c.begin(), x) ;
}
}

You could use std::partition, which will move all elements in a range which meet a given predicate to the beginning of the range, and return an iterator to the first element which doesn't meet the predicate.
template <typename Container, typename Arg>
void move_x(Container& c, Arg x)
{
typename Container::iterator endrange =
std::partition(c.begin(), c.end(), [&x](Arg ele){ return ele == x; });
}
In this case, we're not using the return value but I think it would probably be useful.

The output is wrong. There should be for (auto i:v) cout << i; not v[i]. You would see the garbage with a right algorithm too

You need a loop to process all matches (or use count and insert). v defined as list<int>:
template <typename Container, typename Arg>
void move_x(Container& c, Arg x)
{
for (auto it = find(c.begin(), c.end(), x);
it != c.end();
it = find(it, c.end(), x)) {
c.insert(c.begin(), x);
it = c.erase(it);
}
}

Related

Arbitrary type of container

The task is to write a function filter that takes list (std::list) as the first argument and predicate (std::function) as the second argument. The function needs to return new list which contains all the elements that meet the condition from the predicate.
Then the function needs to be improved with:
std::list with arbitrary type
arbitrary container with arbitrary type
I easily did the main part and first improvement, but could not find the solution for the second improvement even after several days of research. Here is the code for the first improvement (this code works normally):
#include <iostream>
#include <list>
#include <functional>
template <typename T>
std::list<T> filter (std::list<T>& l, std::function<bool(T)> p){
for (auto it = l.begin(); it != l.end(); ++it){
if (p(*it)){
continue;
}
else {
it = l.erase(it);
}
}
return l;
}
int main()
{
std::list<int> initial_list;
for (int i = 0; i <= 50; ++i){
initial_list.push_back(i);
}
std::function<bool(int)> predicate = [](const int& a){
return a % 2 == 0;
};
std::list<int> end_list = filter(initial_list, predicate);
for (auto e : end_list){
std::cout << e << " ";
}
std::cout << std::endl;
return 0;
}
Here is the code I tried for the second improvement:
template <typename T, typename U>
T<U> filter (T<U>& l, std::function<bool(U)> p){
for (auto it = l.begin(); it != l.end(); ++it){
if (p(*it)){
continue;
}
else {
it = l.erase(it);
}
}
return l;
}
But vim says expected unqualified-id and compiler says:
problem5.cpp:6:1: error: ‘T’ is not a template
T<U> filter (T<U>& l, std::function<bool(U)> p){
^
problem5.cpp:6:14: error: ‘T’ is not a template
T<U> filter (T<U>& l, std::function<bool(U)> p){
^
Thank you in advance.
You need a template template parameter to make it compile i.e.
template <template<typename> typename T, typename U>
T<U> filter (const T<U> &l) {
}

C++ generic insert into std container?

If I have the following program:
#include <vector>
#include <set>
template<class T, class U>
void AddToContainer(T& container, U value)
{
container.push_back(value);
}
int main(char**, int)
{
std::vector<int> v;
AddToContainer(v, 1);
std::set<int> s;
AddToContainer(s, 1);
return 0;
}
How can I make the adding to the container generic? Since std::set hasn't got a push_back but only insert, this will fail to compile.
You could use expression SFINAE with a dummy parameter to check if push_back() works:
template <class C, class V>
auto append(C& container, V&& value, int)
-> decltype(container.push_back(std::forward<V>(value)), void())
{
container.push_back(std::forward<V>(value));
}
template <class C, class V>
void append(C& container, V&& value, ...)
{
container.insert(std::forward<V>(value));
}
which your function will just forward to:
template <class C, class V>
void AddToContainer(C& container, V&& value) {
append(container, std::forward<V>(value), 0);
}
If push_back() is a valid expression, the first overload will be preferred since int is a better match for 0 than ... If push_back() isn't a valid expression, then there's only one viable overload.
Whether this is actually a good idea or not is a separate question.
I believe that all* C++ containers (though not the container adapters like priority_queue) have a version of insert that looks like this:
iterator insert(iterator location, T&& value)
For the sequence collections, the location is the actual location; for associative collections (like map and unordered_map), the iterator is a "hint" parameter (for instance, to help a map insert an element quickly if you already know precisely where it belongs in sorted order). However, providing an invalid hint doesn't cause any invalid behavior, so a valid generic insert for C++ collections would be:
template<C, T>
void insert(C& collection, T&& value) {
collection.insert(collection.end(), std::forward<T>(value));
}
* It looks like forward_list is the only one that doesn't have this method, which makes sense.
C++20 style:
template<typename C, typename V>
requires requires (C& c, V&& v) { c.push_back(std::forward<V>(v)); }
auto AddToContainer(C& container, V&& value) {
return container.push_back(std::forward<V>(value));
}
template<typename C, typename V>
requires (requires (C& c, V&& v) { c.insert(c.end(), std::forward<V>(v)); } &&
!requires(C& c, V&& v) { c.push_back(std::forward<V>(v)); })
auto AddToContainer(C& container, V&& value) {
return container.insert(container.end(), std::forward<V>(value));
}
or more succinct but with worse diagnostics:
template<typename C, typename V>
auto AddToContainer(C& container, V&& value)
{
if constexpr (requires (C& c, V&& v) { c.push_back(std::forward<V>(v)); })
return container.push_back(std::forward<V>(value));
else
return container.insert(container.end(), std::forward<V>(value));
}
If you are not worried about the order of elements inserted in the set,
template<typename Container, typename value>
void addelement(Container& C, value v)
{
std::fill_n(std::inserter(C,C.end()), 1,v);
}
int main()
{
std::vector<int> v;
addelement(v, 2);
addelement(v, 4);
addelement(v, 6);
std::set<int> s;
addelement(s, 8);
addelement(s, 6);
addelement(s, 4);
addelement(s, 8);
std::cout << "Vector elements :: " << std::endl;
for (auto item : v)
std::cout << item << std::endl;
std::cout << "Set elements :: " << std::endl;
for (auto item : s)
std::cout << item << std::endl;
return 0;
}

Passing iterators to templates

Sorry for the unclear question. I need to use the following template to sort an array of object belonging to a custom class using the insertion algorithm:
template<typename pointer, typename T, typename Functype>
void sort_array(pointer puntatore, T* obj, int dim, Functype pred){
T val;
for(int i=1; i<dim; i++){
val=obj[i];
for(int j=(i-1); j>=0; j--){
if(pred(obj[j].*puntatore, val.*puntatore)){
obj[j+1]=obj[j];
obj[j]=val;
}
}
}
}
I'm wondering how I can write a more general template that can accept any kind of iterator that points to an object of class T, not just a pointer. Writing T obj in parameter list gives me troubles with the variable T val in the assignment, which in this case would be something like *val=obj[i] being val itself an iterator. Is there any way to tell the template he has to take a generic iterator pointing to an object of class T(i.e. in the same way writing T* tells it to expect a pointer to an object of class T)?
example of how i might use this template
class Example{
int first;
int second;
};
template<typename pointer, typename T, typename Functype>
void sort_array(pointer puntatore, T* obj, int dim, Functype pred){
T val;
for(int i=1; i<dim; i++){
val=obj[i];
for(int j=(i-1); j>=0; j--){
if(pred(obj[j].*puntatore, val.*puntatore)){
obj[j+1]=obj[j];
obj[j]=val;
}
}
}
}
int main(){
Example array[5]={{1,2},{2,4},{1,7},{5,3},{6,7}};
//now i sort the elements in the array by their first element in a decreasing order
sort_array(&Example::first, array, 5, [](int a, int b){return (a<b);});
}
Well you could take inspiration from STL implementations and provide an interface that would take a range instead of an array like below:
template<typename BidirectionalIterator, typename Predicate =
std::less<typename std::iterator_traits<BidirectionalIterator>::value_type>>
void
insertion_sort(BidirectionalIterator first, BidirectionalIterator last,
Predicate pred = {}) {
if(first != last) {
auto it = first;
while(++it != last) {
auto it2 = it;
while(it2 != first) {
auto it3 = it2;
--it3;
if(pred(*it2, *it3)) {
std::swap(*it2, *it3);
} else {
break;
}
--it2;
}
}
}
}
Live Demo
Mind however, that you could also provide overloaded operator< or operator> for your objects for this to work with standard predicates:
bool
operator<(T const &A, T const &B) {
return A.*puntatore < B.*puntatore;
}
bool
operator>(T const &A, T const &B) {
return A.*puntatore < B.*puntatore;
}

Pass iterator as a function parameter

I try to write a function, which will sum the elements of a container. This container can be Vector, List, Queue, etc... That's why I tried templates.
Unfortunately I get this error:
'C' is not a template
Source:
#include <iostream>
#include <vector>
using namespace std;
template<class C, typename T>
T sum( C<T>::iterator begin, C<T>::iterator end ) {
T s = null;
for (C<T>::iterator it = begin; it != end; it++) {
s += *it;
}
return s;
}
int main()
{
vector<int> v = {5, 9, 0, 11};
cout << sum(v.begin(), v.end()) << endl;
return 0;
}
What do I wrong? How should I fix it?
You could express the whole thing in terms of a iterator type, and use iterator_traits to get the value_type:
#include <iterator>
template<typename Iterator>
typename std::iterator_traits<Iterator>::value_type
sum(Iterator begin, Iterator end)
{
using value_type = typename std::iterator_traits<Iterator>::value_type;
value_type s = value_type();
for (Iterator it = begin; it != end; it++) {
s += *it;
}
return s;
}
In real life, use std::accumulate:
int sum = std::accumulate(v.begin(), v.end(), 0);
The particular error you get is because you'd need a template template argument:
template<template <typename> class C, typename T>
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^
T sum( C<T>::iterator begin, C<T>::iterator end )
However, the standard containers typically have more than just one template argument:
template < class T, class Alloc = allocator<T> > class vector
and it is a bit non-trivial to write such function correctly. You could use variadic template arguments, or you could do like the standard library does, and only specialize as much as you really need:
// <algorithm>
namespace std {
template <class RandomAccessIterator>
void sort (RandomAccessIterator first, RandomAccessIterator last);
}
In your case (pretending that your need is not covered by the standard algorithms library already):
template <typename Iterator>
auto sum(Iterator begin, Iterator end)
-> decltype(*begin+*begin) // the type of summing two of them
{
if (begin == end) throw std::logic_error("....");
auto s = *begin;
++begin;
for (; begin != end; ++begin) {
s += *begin;
}
return s;
}
There are some more differences from your original code:
the new code does not assume a null or a default constructor defined (T s = null;)
does not introduce additional iterator (it)
uses pre-increment
throws an exception when begin==end
If you add an init parameter, you can make it almost noexcept:
template <typename Iterator, typename T>
T sum(Iterator begin, Iterator end, T init)
{
for (; begin!=end; ++begin)
init += *begin;
return init;
}
But only almost, because init += *begin could still throw.
If you have such signature, you've by the way reproduced the signature of std::accumulate.

How to slice with for-range loop ? C++0x

Using range based for loops in C++0X, I know we'll be able to do :
std::vector<int> numbers = generateNumbers();
for( int k : numbers )
{
processNumber( k );
}
(might be even simpler to write with lambda)
But how should i do if I only want to apply processNumber( k ) to a part of numbers? For example, how should I write this for loop for to apply processNumber() to the half (head or tail) of the numbers? Is "slicing" allowed like in Python or Ruby?
You can use the "sliced" range adaptor from the Boost.Range library:
#include <boost/range/adaptor/sliced.hpp>
using boost::adaptors::sliced;
...
std::vector<int> numbers = generateNumbers();
for( int k : numbers | sliced(0, numbers.size() / 2))
{
processNumber( k );
}
One possibility might be boost's iterator_range
(Not having a compiler which supports range-based for, using BOOST_FOREACH instead. I'd expect range-based for work the same, as long as the container or range has the begin and end method.)
#include <boost/foreach.hpp>
#include <boost/range/iterator_range.hpp>
#include <iostream>
#include <vector>
int main()
{
std::vector<int> v{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
BOOST_FOREACH(int n, boost::make_iterator_range(v.begin(), v.begin() + v.size() / 2)) {
std::cout << n << '\n';
}
}
For convenience you could also make your own slice function, so it would accept indices instead of iterators. Again, it could be based on boost.iterator_range, or not:
#include <cstddef>
#include <iterator>
template <class Iterator>
class iter_pair
{
public:
typedef Iterator iterator;
typedef Iterator const_iterator; //BOOST_FOREACH appears to want this
iter_pair(iterator first, iterator last): first(first), last(last) {}
iterator begin() const { return first; }
iterator end() const { return last; }
private:
iterator first, last;
};
template <class Container>
struct iterator_type
{
typedef typename Container::iterator type;
};
template <class Container>
struct iterator_type<const Container>
{
typedef typename Container::const_iterator type;
};
template <class Container>
iter_pair<typename iterator_type<Container>::type>
slice(Container& c, size_t i_first, size_t i_last)
{
typedef typename iterator_type<Container>::type iterator;
iterator first = c.begin();
std::advance(first, i_first);
iterator last = first;
std::advance(last, i_last - i_first);
return iter_pair<iterator>(first, last);
}
template <class Container>
iter_pair<typename iterator_type<Container>::type>
slice(Container& c, size_t i_last)
{
return slice(c, 0, i_last);
}
//could probably also be overloaded for arrays
#include <cctype>
#include <string>
#include <boost/foreach.hpp>
#include <iostream>
int main()
{
std::string s("Hello world, la-la-la!");
BOOST_FOREACH( char& c, slice(s, 2, 11)) {
if (c == 'l')
c = std::toupper(c);
}
const std::string& r = s;
BOOST_FOREACH( char c, slice(r, r.size() - 1) ) {
std::cout << c << " ";
}
std::cout << '\n';
}
Generally one would probably be working with iterators in the first place, so it might not be that useful.
Something like this may work (unchecked as I don't have access to a C++0x compiler),
Edit: Checked it on VS10, of course I had to fix numurous errors....
Define a class which is a proxy to any container and whose iterators only return a subset of the container. The example I supply is the simplest one giving the first half but it can be made much more general.
template <class Container>
class head_t {
Container& c_;
public:
template <class T>
class iter {
T curr_;
const T& end_;
int limit_; // count how many items iterated
public:
iter(T curr, const T& end)
: curr_(curr)
, end_(end)
, limit_(std::distance(curr_, end_)/2)
{ }
typename Container::value_type operator*() { return *curr_; }
// Do the equivilant for for operator++(int)
iter& operator++() {
if (--limit_ == 0) // finished our slice
curr_ = end_;
else
++curr_;
return *this;
}
bool operator!=(const iter& i) const {
return curr_ != i.curr_;
}
};
head_t(Container& c) : c_(c) {}
iter<typename Container::iterator> begin() {
return iter<typename Container::iterator>(c_.begin(), c_.end());
}
iter<typename Container::iterator> end() {
return iter<typename Container::iterator>(c_.end(), c_.end());
}
};
template <class T>
head_t<T> head(T& t) { return head_t<T>(t); }
And then you use it in the loop:
for( int k : head(numbers) )