Passing iterators to templates - c++

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;
}

Related

How to implement a function that accepts any container type?

I want to implement a function that takes std::vector or std::array as an argument. How can the parameter list abstract from the container type?
See this example:
// how to implement this?
bool checkUniformity(container_type container)
{
for(size_t i = 1; i < container.size(); i++)
{
const auto& o1 = container[i-1];
const auto& o2 = container[i];
if(!o1.isUniform(o2))
return false;
}
return true;
}
struct Foo
{
bool isUniform(const Foo& other);
}
// I want to call it in both ways:
std::vector<Foo> vec;
std::array<Foo> arr;
bool b1 = checkUniformity(vec);
bool b2 = checkUniformity(arr);
What is the best and most readable way to do this?
Any suggestions for code improvement (style, design) are welcome as well. Thanks!
If you use iterators and ranges instead of working with the container directly, you can produce an algorithm that works with any container (including linked lists) efficiently and also with streams:
#include <list>
#include <array>
#include <vector>
#include <iterator>
template <typename T>
bool checkUniformity(T begin, T end) {
// Check for empty range
if (begin == end) return true;
// Remember last element
T last = begin;
while (++begin != end) {
if (!((*last).isUniform(*begin)))
return false;
last = begin;
}
return true;
}
template <typename T, typename F>
bool checkUniformity(T begin, T end, F pred) {
// Check for empty range
if (begin == end) return true;
// Remember last element
T last = begin;
while (++begin != end) {
if (!pred(*last, *begin))
return false;
last = begin;
}
return true;
}
struct Foo
{
bool isUniform(const Foo& other) const;
};
int main () {
// I want to call it in both ways:
std::vector<Foo> vec;
std::array<Foo, 3> arr;
std::list<Foo> list;
Foo carr [3];
bool b1 = checkUniformity(std::cbegin(vec), std::cend(vec));
bool b2 = checkUniformity(std::cbegin(arr), std::cend(arr));
bool b3 = checkUniformity(std::cbegin(list), std::cend(list));
bool b4 = checkUniformity(std::cbegin(carr), std::cend(carr));
bool b1_2 = checkUniformity(std::cbegin(vec), std::cend(vec), [] (const Foo& a, const Foo& b) { return a.isUniform(b); });
bool b2_2 = checkUniformity(std::cbegin(arr), std::cend(arr), [] (const Foo& a, const Foo& b) { return a.isUniform(b); });
bool b3_2 = checkUniformity(std::cbegin(list), std::cend(list), [] (const Foo& a, const Foo& b) { return a.isUniform(b); });
bool b4_2 = checkUniformity(std::cbegin(carr), std::cend(carr), [] (const Foo& a, const Foo& b) { return a.isUniform(b); });
}
You can also implement a second variant as shown, where you can specify the condition as a predicate (e.g. a lambda, as shown) in case you have different variants of isUniform. Having to pass two parameters for the range instead of just the container is slightly more cumbersome, but much more flexible; it also allows you to run the algorithm on a sub-range of the container.
This is the same approach as used by standard-library algorithms, such as std::find.
You want template:
template <typename container_type>
bool checkUniformity(const container_type& container)
{
for(size_t i = 1; i < container.size(); i++)
{
const auto& o1 = container[i-1];
const auto& o2 = container[i];
if(!o1.isUniform(o2))
return false;
}
return true;
}
To accept almost any container type is a good idea to use templates with template template parameters. Most of the containers in C++ accept as the fist template parameter the value type that they hold, and an allocator type, which is used to allocate memory.
To check wether the value type of the container implements a certain method, isUniform() in you case, you can use std::enable_if.
#include <iostream>
#include <vector>
#include <type_traits>
struct Foo
{
bool isUniform(const Foo&) const { return true; }
};
//Template template parameter TContainer, that accepts 2 template parameters
//the first for the value_type, the second for the allocator type
template <template <typename, typename> typename TContainer, typename TValue, typename TAllocator>
auto checkUniformity(TContainer<TValue, TAllocator>& container)
//Using `std::enable_if` to check if the result of invoking the `isUniform()` method is bool
//in case it is not bool, or the method does not exist, the `std::enable_if_t` will result
//in an error
-> std::enable_if_t
<
std::is_same_v
<
decltype(std::declval<TValue>().isUniform(std::declval<TValue>())),
bool
>,
bool
>
{
for(size_t i = 1; i < container.size(); i++)
{
const auto& o1 = container[i-1];
const auto& o2 = container[i];
if(!o1.isUniform(o2))
return false;
}
return true;
}
int main()
{
std::vector<Foo> vec(10);
std::cout << std::boolalpha << checkUniformity(vec);
return 0;
}
Note that std::array does not have an allocator type, so this method will not work with std::array.
For that you may change TContainer to a simple template type parameter, and use typename TContainer::value_type wherever you would use TValue.

C++: Supplying a templated compare function to std::sort

Suppose I want to get std::sort to sort a vector of pointers to int's, based on the value of the int's the pointers point to. Ignore the obvious performance issue there. Simple huh?
Make a function:
bool sort_helper(const int *a, const int *b)
{
return *a < *b;
}
and supply to the std::sort.
Now, if we also want to do the same thing with a vector of pointers to large objects. The same thing applies:
first we define a < operator in the object, then make a function along the following lines:
bool sort_helper(const ob_type *a, const ob_type *b)
{
return *a < *b;
}
or whatever, supply that to std::sort.
Now, and this is where it gets tricky: what if we want to sort a vector of pointers to any type, with any arbitrary compare function (we make the assumption that whatever type we use that function with, will be able to work with it)- supplying a template version of the sort_helper function above is easy:
template <class ob_type>
bool sort_helper(const ob_type *a, const ob_type *b)
{
return *a < *b;
}
However, supplying an arbitrary compare function is harder: Something like this-
template <typename comparison_function, class ob_type>
bool sort_template_helper(const ob_type *a, const ob_type *b)
{
return comparison_function(*a, *b);
}
template <typename comparison_function, class iterator_type>
void t_sort(const iterator_type &begin, const iterator_type &end, comparison_function compare)
{
std::sort(begin, end, sort_template_helper<compare>);
}
is what I'd like to do, but doing this:
bool less_than(const int a, const int b)
{
return a < b;
}
void do_stuff()
{
t_sort(ipoint_vector.begin(), ipoint_vector.end(), sort_template_helper<less_than>);
}
Doesn't work.
How can I sort a vector of pointers to a known type, by the value of the objects pointed to, using an arbitrary comparison function, supplied to std::sort? Assume that the test case I am presenting here is an insanely simplified version of the actual scenario, and that there are valid reasons for wanting to do things this way, that would take too long to go into and distract from the problem.
[EDIT: for various reasons, am looking for a solution that also works in C++03 - Thanks to Nir for his C++14 answer tho']
Basically what you need is a higher order function: a function that returns a function.
template <class T, class F>
auto make_pointee_comparison(F f) {
return [=] (T const * l, T const * r) { return f(*l, *r); };
}
Here I have T be explicitly specified; you might be able with extra programming to deduce T but it can be quite tricky to make it work correctly for both function objects and function pointers.
Edit: to make this work in C++03, we have to obviously remove our usage of lambdas. Converting a lambda to a function object is pretty straightforward though. We declare a struct:
template <class F>
struct PointeeComparisonHelper {
PointeeComparisonHelper(F f) : m_f(f) {}
template <class T>
bool operator()(T const * l, T const * r) const {
return m_f(*l, *r);
}
F m_f;
};
template <class F>
PointeeComparisonHelper<F> make_pointee_comparison(F f) {
return PointeeComparisonHelper<F>(f);
}
Edit: I templated the call operator in the 03 example; to do this with a lambda you need C++14, not just 11. If you are using the 03 form, then you don't need to explicitly specify <int> to make_pointee_comparison.
Usage:
auto c = make_pointee_comparison<int>([] (int x, int y) { return x < y; });
int x = 5;
int y = 6;
std::cerr << c(&x, &y) << c(&y, &x);
Which prints 10 (true false). Note that this takes a function object rather than a function pointer, which is more idiomatic in C++. But you can pass a function pointer too:
bool compare(int x, int y) { return x > y; }
auto c2 = make_pointee_comparison<int>(&compare);
std::cerr << c2(&x, &y) << c2(&y, &x);
You could then write your function like this:
template <typename comparison_function, class iterator_type>
void t_sort(const iterator_type &begin, const iterator_type &end, comparison_function compare)
{
using deref_type = const decltype(*begin);
std::sort(begin, end, make_pointee_comparison<deref_type>(compare));
}
You cannot pass function template pointer in c++, what you can do is to create functor with operator() template (something very similar to lambda with auto parameters):
#include <algorithm>
#include <vector>
#include <cassert>
struct less {
template <class T>
bool operator()(T first, T second) const {
return first < second;
}
};
template <class Cmp>
struct cmp_ptr {
Cmp cmp;
cmp_ptr(Cmp cmp):cmp(cmp) { }
cmp_ptr() { }
template <class T>
bool operator()(T first, T second) const {
return cmp(*first, *second);
}
};
template <class Iter, class Cmp>
bool is_sorted(Iter beg, Iter end, Cmp cmp) {
Iter prev = beg;
Iter next = beg;
for (next++; next != end; prev++, next++) {
if (cmp(*next, *prev)) {
return false;
}
}
return true;
}
int main() {
std::vector<int*> v;
v.push_back(new int(10));
v.push_back(new int(1));
v.push_back(new int(5));
v.push_back(new int(7));
v.push_back(new int(3));
v.push_back(new int(2));
std::sort(v.begin(), v.end(), cmp_ptr<less>());
assert(::is_sorted(v.begin(), v.end(), cmp_ptr<less>()));
}
[live demo]
Remember that operator must have const qualifier to make caller to be able to access to it from temporary object.
guess you are looking for something like this:
template <typename comparison_function, class iterator_type>
void sort_deref(const iterator_type &begin, const iterator_type &end, comparison_function compare) {
std::sort(begin, end, [compare](auto *a, auto *b) { compare(*a,*b); });
}
// example usage:
sort_deref(std::begin(container), std::end(container), std::less<>());
You are trying to pass value of type comparison_function to a template expecting type.

Applying conditions to the whole vector

I need to have a while loop that applies a logic condition to every element of a vector.
For example, while(all elements < 3) or while(all elements != 3)
The only way I can think of is write while(vector[1]!=3 || vector[2]!=3 || ...). That would quickly grow if my vector is large.
Are there better way of doing this in C++?
See std::all_of
Assuming
std::vector<int> v;
if(std::all_of(v.cbegin(), v.cend(), [](int i){ return i < 3 }))
{
}
if(std::all_of(v.cbegin(), v.cend(), [](int i){ return i != 3 }))
{
}
Pre-C++11
struct Check
{
int d;
Check(int n) : d(n) {}
bool operator()(int n) const
{ return n < d; }
};
// Copied from above link
template< class InputIt, class UnaryPredicate >
bool all_of(InputIt first, InputIt last, UnaryPredicate p)
{
for (; first != last; ++first) {
if (!p(*first)) {
return false;
}
}
return true ;
}
if( all_of(v.begin(), v.end(), Check(3) ))
{
}
In C++11, the answer is essentially using std::all together with lambdas:
if (std::all(v.begin(),v.end(),[](const typename std::decay::type& a)
{ return a<3; })
{ 7* your stuff here */ }
In C++03, you have to workout std::all and the lambdas:
template<class Iter, Fn>
bool all(Iter i, Iter end, Fn fn)
{
for(;i!=end; ++i)
if(!fn(*i)) return false;
return true;
}
and for <3 you need an explicit class like
class is_less_than_val
{
int val;
public:
is_less_than(int value) :val(value) {}
bool operator()(int var) const { return var<val; }
};
so that you can write
if(all(v.begin(),v.end(),is_less_than_val(3))
{ /* your stuff here */ }
In case you find all the functinal machinery obscure (C++03 is not that "easy", having no substantial type deduction), and prefer a more procedural approach,
template<class Cont, class Val>
bool all_less_than(const Cont& c, const Val& v)
{
for(typename Cont::const_iterator i=c.cbegin(), i!=c.end(); ++i)
if(!(*i < v)) return false;
return true;
}
template<class Cont, class Val>
bool all_equal_to(const Cont& c, const Val& v)
{
for(typename Cont::const_iterator i=c.cbegin(), i!=c.end(); ++i)
if(!(*i == v)) return false;
return true;
}
In all the samples, whatever the code is arranged, everything boils down into a loop that breaks as false on the negation of the searched condition.
Of course, if all are numerical comparison, !(<) is >= and !(==) is !=, but since Cont and Val are template parameters, using only < and == result is less requirements for Val implementation (that can be anything, not just int)
As others have said, in C++11, there are special functions for
this. In pre-C++11, the usual idiom would have involved
std::find_if, and a comparison with the end iterator on the
results, e.g.:
struct Condition
{
// The condition here must be inversed, since we're looking for elements
// which don't meet it.
bool operator()( int value ) const { return !(value < 3); }
};
// ...
while ( std::find_if( v.begin(), v.end(), Condition() ) == v.end() ) {
// ...
}
This is such a common idiom that I continue to use it in C++11
(although often with a lambda).

Template for iterator type

I want to create a template method for adding and counting of elements in a map (stl) independently from element type. The question is: can I use a template for the iterator type as shown below?
template < typename Type, typename Iter >
void TextStat::addElement(Type element, map<Type, int> map, Iter &it) {
it = map.find(element);
if ( it == map.end() ) {
map.insert(pair<Type, int>(element, 1));
} else {
it->second += 1;
}
}
You may write your method like this:
template <typename Type>
void TextStat::addElement(const Type& element, std::map<Type, int>& m) {
std::map<Type, int>::iterator it = m.find(element);
if (it == m.end()) {
m.insert(std::pair<Type, int>(element, 1));
} else {
it->second += 1;
}
}
or even simpler, as default value initialization of int is 0:
template <typename Type>
void TextStat::addElement(const Type& element, std::map<Type, int>& m) {
m[element]++;
}

moving elements in a vector is not working as expected

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);
}
}