pointer to reference adaptor

S

Stanislaw Salik

Hi,

Lets suppose we want to use generic algotithms on collections of
pointers (both raw and smart). For example, we want to sort a vector of
(smart)pointers. We need a comparator that will take two pointers and
return a bool.

std::vector<std::string *> v;
std::sort(v.begin(), v.end(), std::less<int>());

The code above will noc compile, since std::less<std::string>() object
takes two strings, while we have pointers to std::string. So we need an
adaptor.

template <class T, class U>
struct pointer_to_ref
{
typedef T argument_type;
typedef U result_type;

inline
result_type & operator() (argument_type obj)
{
return *obj;
}
};

std::vector<int *> v;
std::sort(v.begin(), v.end(),
boost::bind(std::less<string>(),
boost::bind (pointer_to_ref<std::string*, std::string>(),_1),
boost::bind (pointer_to_ref<std::string*, std::string>(),_2)));

And the code will just work fine.

And here goes my question. Since there are so many places where
pointer_to_ref (and pointer_to_value probably) would be useful, is there
any standard class that does the same thing?

For example, for smart pointers i can use
&collection_type::value_type::eek:perator* as an adaptor. But what if i
wanted to make code more generic and working with raw pointers too?

Regards,
Stanislaw
 
J

Jonathan Turkanis

Stanislaw Salik said:
Hi,

Lets suppose we want to use generic algotithms on collections of
pointers (both raw and smart). For example, we want to sort a vector of
(smart)pointers. We need a comparator that will take two pointers and
return a bool.

template <class T, class U>
struct pointer_to_ref
{
typedef T argument_type;
typedef U result_type;

inline
result_type & operator() (argument_type obj)
{
return *obj;
}
};
And here goes my question. Since there are so many places where
pointer_to_ref (and pointer_to_value probably) would be useful, is there
any standard class that does the same thing?

First, for the example you gave -- which is a common situation -- you
should be able to use indirect_iterators
(http://www.boost.org/libs/iterator/doc/indirect_iterator.html)

Second, I don't think it's necessary to have two template parameters.
You should be able to calculate the result type given the argument
type (see http://www.boost.org/boost/pointee.hpp.)

Jonathan
 
S

Stanislaw Salik

Thanks for the information.

Jonathan said:
First, for the example you gave -- which is a common situation -- you
should be able to use indirect_iterators
(http://www.boost.org/libs/iterator/doc/indirect_iterator.html)

The indirect_iterator adaptor works fine. However, the resulting
algorithm is a bit different. With indirect_iterator, std::sort works on
objects (in this case integers), while the approach with
pointer_to_reference adaptors works on (smart)pointers.

In the example1.cpp below outputs

vect: 8 0 5 9 1 6 3 4 7 2
copy: 0 1 2 3 4 5 6 7 8 9
vect: 0 1 2 3 4 5 6 7 8 9
copy: 0 1 2 3 4 5 6 7 8 9


vect: 6 1 7 4 2 0 8 5 9 3
copy: 0 1 2 3 4 5 6 7 8 9
vect: 0 1 2 3 4 5 6 7 8 9
copy: 5 1 4 9 3 7 0 2 6 8

Notice that the copy becomes permuted while the original was sorted.

Is there a way to use indirect_iterator in such way that sort replaces
pointers instead of pointed values?

Jonathan said:
Second, I don't think it's necessary to have two template parameters.
You should be able to calculate the result type given the argument
type (see http://www.boost.org/boost/pointee.hpp.)

This makes the code a bit cleaner. Is there a way to create adaptor
object straight from the pointee<> template? Or is it still necessary to
declare structure that does the trick?

Regards,
Stanislaw

example1.cpp

#include <algorithm>
#include <iostream>
#include <iterator>
#include <vector>

#include <stdlib.h>

#include <boost/iterator/indirect_iterator.hpp>
#include <boost/bind.hpp>

template <class T>
struct pointer_to_ref
{
typedef T argument_type;
typedef typename boost::pointee<T>::type & result_type;

inline
result_type operator() (argument_type obj)
{
return *obj;
}
};

struct counter
{
typedef int* result_type;

counter () :n (0) {}
result_type operator() () { return new int (n++); }

int n;
};

typedef std::vector<int *> vector_t;


int
main ()
{
srand(time(0));

vector_t v;

std::generate_n (std::back_insert_iterator<vector_t>(v), 10,
counter());

vector_t w (v);

std::random_shuffle (v.begin(), v.end());

std::cout << "vect: ";
std::copy (boost::make_indirect_iterator(v.begin()),
boost::make_indirect_iterator(v.end()),
std::eek:stream_iterator<int>(std::cout, " "));
std::cout << std::endl;

std::cout << "copy: ";
std::copy (boost::make_indirect_iterator(w.begin()),
boost::make_indirect_iterator(w.end()),
std::eek:stream_iterator<int>(std::cout, " "));
std::cout << std::endl;

std::sort (v.begin(),
v.end(),
boost::bind(std::less<int>(),

boost::bind(pointer_to_ref<vector_t::value_type>(), _1),

boost::bind(pointer_to_ref<vector_t::value_type>(), _2)));

std::cout << "vect: ";
std::copy (boost::make_indirect_iterator(v.begin()),
boost::make_indirect_iterator(v.end()),
std::eek:stream_iterator<int>(std::cout, " "));
std::cout << std::endl;

std::cout << "copy: ";
std::copy (boost::make_indirect_iterator(w.begin()),
boost::make_indirect_iterator(w.end()),
std::eek:stream_iterator<int>(std::cout, " "));
std::cout << std::endl;

return 0;
}



example2.cpp:

#include <algorithm>
#include <iostream>
#include <iterator>
#include <vector>

#include <stdlib.h>

#include <boost/iterator/indirect_iterator.hpp>


struct counter
{
typedef int* result_type;

counter () :n (0) {}
result_type operator() () { return new int (n++); }

int n;

};

typedef std::vector<int *> vector_t;

int
main ()
{
srand(time(0));

vector_t v;

std::generate_n (std::back_insert_iterator<vector_t>(v), 10,
counter());

vector_t w (v);

std::random_shuffle (v.begin(), v.end());

std::cout << "vect: ";
std::copy (boost::make_indirect_iterator(v.begin()),
boost::make_indirect_iterator(v.end()),
std::eek:stream_iterator<int>(std::cout, " "));
std::cout << std::endl;

std::cout << "copy: ";
std::copy (boost::make_indirect_iterator(w.begin()),
boost::make_indirect_iterator(w.end()),
std::eek:stream_iterator<int>(std::cout, " "));
std::cout << std::endl;

std::sort (boost::make_indirect_iterator(v.begin()),
boost::make_indirect_iterator(v.end()),
std::less<int>());

std::cout << "vect: ";
std::copy (boost::make_indirect_iterator(v.begin()),
boost::make_indirect_iterator(v.end()),
std::eek:stream_iterator<int>(std::cout, " "));
std::cout << std::endl;

std::cout << "copy: ";
std::copy (boost::make_indirect_iterator(w.begin()),
boost::make_indirect_iterator(w.end()),
std::eek:stream_iterator<int>(std::cout, " "));
std::cout << std::endl;

return 0;
}
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,431
Messages
2,571,679
Members
48,796
Latest member
Greg L.

Latest Threads

Top