What I am doing
I am practicing c++ after 3 years. I needed to learn fast and broadly, so this example i am trying to solve might look odd to you.
I am using c++20, gcc 10.2.
I wanted to make a pythonic enumerate function that
Takes any container<T>
Yields std::tuple<int, T>
Where T is the type of items in the container
I wanted to try applying pythonic range as an argument of enumerate which
Takes (int start, int end, int step)
Yields int i from start to end every step
range (Not my code, I only added step functionality)
template <typename T>
class range_iterator;
template <typename T>
class range_impl
{
const T start_;
const T stop_;
const T step_;
public:
range_impl(T start, T stop, T step) : start_{start}, stop_{stop}, step_{step} {};
range_impl(T start, T stop) : start_{start}, stop_{stop}, step_{1} {};
range_impl(T stop) : start_{0}, stop_{stop}, step_{1} {};
range_iterator<T> begin() const
{
return range_iterator<T>{start_, step_};
}
range_iterator<T> end() const
{
return range_iterator<T>{stop_, step_};
}
};
template <typename T>
class range_iterator
{
T current_;
const T step_;
public:
range_iterator(T init, T step) : current_{init}, step_{step} {};
range_iterator<T> &operator++()
{
current_ += step_;
return *this;
}
bool operator!=(const range_iterator<T> &rhs) const
{
return current_ != rhs.current_;
}
T operator*() const
{
return current_;
}
};
template <typename T>
range_impl<T> range(const T start, const T stop, const T step)
{
return range_impl<T>(start, stop, step);
}
template <typename T>
range_impl<T> range(const T start, const T stop)
{
return range_impl<T>(start, stop);
}
template <typename T>
range_impl<T> range(const T stop)
{
return range_impl<T>(stop);
}
Can be used like following
#include <iostream>
int main()
{
for(auto i: range(0, 100 2)
{
std::cout << i << std::endl;
}
}
Problem code: enumerate
template <typename T>
class enumerate_iterator;
// Here, T should be a type of a container that contains type X
template <typename T>
class enumerate_impl
{
T impl;
public:
enumerate_impl<T>(T impl) : impl{impl} {/* empty */};
enumerate_iterator begin() const
{
return enumerate_iterator{impl.begin()};
}
enumerate_iterator end() const
{
return enumerate_iterator{impl.end()};
}
};
// Here, T should be a type of a iterator, I think. Confused myself.
template <typename T>
class enumerate_iterator
{
T iterator;
int i;
public:
enumerate_iterator(T iterator) : iterator{iterator}, i{0} {/* empty body */};
enumerate_iterator<T> &operator++()
{
i++;
iterator++;
return *this;
}
bool operator!=(const enumerate_iterator<T> &rhs) const
{
return iterator != rhs.iterator;
}
std::tuple operator*() const
{
return {i, *iterator};
}
};
template <typename T>
enumerate_impl<T> enumerate(T impl)
{
return enumerate_impl<T>{impl};
}
Expected usage
#include <iostream>
int main()
{
for (auto &[i, j] : enumerate(range(0, 100, 2)))
{
std::cout << i << " " << j << std::endl;
}
}
Gotten error (There actually tons of compilation error, but I want to try more on the others).
utility.cpp:186:20: error: deduced class type 'tuple' in function return type
186 | std::tuple operator*() const
I guessed this is complaining that you didn't tell me what type the tuple contains. But the thing is, I don't know what type T iterator contains. How would I tell return type is std::tuple<int, type T contains>?
Thanks for reading this long long question.
I think that perhaps, for enumerate_iterator, you might want its template type T to be a "base element type", not some compound "iteration type".
For example, if you were to choose to implement your iteration using raw memory pointers, then the enumerate_iterator's data member called iterator would have type T* (instead of its current T type).
And then, in that case, the definition of operator*() would be programmed as having a return type of std::tuple<int,T>
I know how to sort a vector of pairs, but how do you sort a pair of vectors? I can think of writing a custom "virtual" iterator over a pair of vectors and sorting that, but that seems quite complex. Is there an easier way? Is there one in C++03? I would like to use std::sort.
This problem arises when processing some data generated in hardware, where a pair of arrays makes more sense than array of pairs (since then there would be all kinds of stride and alignment problems). I realize that otherwise keeping a pair of vector instead of a vector of pairs would be a design flaw (the structure of arrays problem). I'm looking for a fast solution, copying the data to a vector of pairs and then back (I will return it to the HW to do more processing) is not an option.
Example:
keys = {5, 2, 3, 1, 4}
values = {a, b, d, e, c}
and after sorting (by the first vector):
keys = {1, 2, 3, 4, 5}
values = {e, b, d, c, a}
I refer to a "pair of vectors" as the pair of keys and values (stored as e.g. std::pair<std::vector<size_t>, std::vector<double> >). The vectors have the same length.
Let's make a sort/permute iterator, so that we can just say:
int keys[] = { 5, 2, 3, 1, 4 };
char vals[] = { 'a', 'b', 'd', 'e', 'c' };
std::sort(make_dual_iter(begin(keys), begin(vals)),
make_dual_iter(end(keys), end(vals)));
// output
std::copy(begin(keys), end(keys), std::ostream_iterator<int> (std::cout << "\nKeys:\t", "\t"));
std::copy(begin(vals), end(vals), std::ostream_iterator<char>(std::cout << "\nValues:\t", "\t"));
See it Live On Coliru, printing
Keys: 1 2 3 4 5
Values: e b d c a
Based on the idea here, I've implemented this:
namespace detail {
template <class KI, class VI> struct helper {
using value_type = boost::tuple<typename std::iterator_traits<KI>::value_type, typename std::iterator_traits<VI>::value_type>;
using ref_type = boost::tuple<typename std::iterator_traits<KI>::reference, typename std::iterator_traits<VI>::reference>;
using difference_type = typename std::iterator_traits<KI>::difference_type;
};
}
template <typename KI, typename VI, typename H = typename detail::helper<KI, VI> >
class dual_iter : public boost::iterator_facade<dual_iter<KI, VI>, // CRTP
typename H::value_type, std::random_access_iterator_tag, typename H::ref_type, typename H::difference_type>
{
public:
dual_iter() = default;
dual_iter(KI ki, VI vi) : _ki(ki), _vi(vi) { }
KI _ki;
VI _vi;
private:
friend class boost::iterator_core_access;
void increment() { ++_ki; ++_vi; }
void decrement() { --_ki; --_vi; }
bool equal(dual_iter const& other) const { return (_ki == other._ki); }
typename detail::helper<KI, VI>::ref_type dereference() const {
return (typename detail::helper<KI, VI>::ref_type(*_ki, *_vi));
}
void advance(typename H::difference_type n) { _ki += n; _vi += n; }
typename H::difference_type distance_to(dual_iter const& other) const { return ( other._ki - _ki); }
};
Now the factory function is simply:
template <class KI, class VI>
dual_iter<KI, VI> make_dual_iter(KI ki, VI vi) { return {ki, vi}; }
Note I've been a little lazy by using boost/tuples/tuple_comparison.hpp for the sorting. This could pose a problem with stable sort when multiple key values share the same value. However, in this case it's hard to define what is "stable" sort anyways, so I didn't think it important for now.
FULL LISTING
Live On Coliru
#include <boost/iterator/iterator_adaptor.hpp>
#include <boost/tuple/tuple_comparison.hpp>
namespace boost { namespace tuples {
// MSVC might not require this
template <typename T, typename U>
inline void swap(boost::tuple<T&, U&> a, boost::tuple<T&, U&> b) noexcept {
using std::swap;
swap(boost::get<0>(a), boost::get<0>(b));
swap(boost::get<1>(a), boost::get<1>(b));
}
} }
namespace detail {
template <class KI, class VI> struct helper {
using value_type = boost::tuple<typename std::iterator_traits<KI>::value_type, typename std::iterator_traits<VI>::value_type>;
using ref_type = boost::tuple<typename std::iterator_traits<KI>::reference, typename std::iterator_traits<VI>::reference>;
using difference_type = typename std::iterator_traits<KI>::difference_type;
};
}
template <typename KI, typename VI, typename H = typename detail::helper<KI, VI> >
class dual_iter : public boost::iterator_facade<dual_iter<KI, VI>, // CRTP
typename H::value_type, std::random_access_iterator_tag, typename H::ref_type, typename H::difference_type>
{
public:
dual_iter() = default;
dual_iter(KI ki, VI vi) : _ki(ki), _vi(vi) { }
KI _ki;
VI _vi;
private:
friend class boost::iterator_core_access;
void increment() { ++_ki; ++_vi; }
void decrement() { --_ki; --_vi; }
bool equal(dual_iter const& other) const { return (_ki == other._ki); }
typename detail::helper<KI, VI>::ref_type dereference() const {
return (typename detail::helper<KI, VI>::ref_type(*_ki, *_vi));
}
void advance(typename H::difference_type n) { _ki += n; _vi += n; }
typename H::difference_type distance_to(dual_iter const& other) const { return ( other._ki - _ki); }
};
template <class KI, class VI>
dual_iter<KI, VI> make_dual_iter(KI ki, VI vi) { return {ki, vi}; }
#include <iostream>
using std::begin;
using std::end;
int main()
{
int keys[] = { 5, 2, 3, 1, 4 };
char vals[] = { 'a', 'b', 'd', 'e', 'c' };
std::sort(make_dual_iter(begin(keys), begin(vals)),
make_dual_iter(end(keys), end(vals)));
std::copy(begin(keys), end(keys), std::ostream_iterator<int> (std::cout << "\nKeys:\t", "\t"));
std::copy(begin(vals), end(vals), std::ostream_iterator<char>(std::cout << "\nValues:\t", "\t"));
}
Just for comparison, this is how much code the split iterator approach requires:
template <class V0, class V1>
class CRefPair { // overrides copy semantics of std::pair
protected:
V0 &m_v0;
V1 &m_v1;
public:
CRefPair(V0 &v0, V1 &v1)
:m_v0(v0), m_v1(v1)
{}
void swap(CRefPair &other)
{
std::swap(m_v0, other.m_v0);
std::swap(m_v1, other.m_v1);
}
operator std::pair<V0, V1>() const // both g++ and msvc sort requires this (to get a pivot)
{
return std::pair<V0, V1>(m_v0, m_v1);
}
CRefPair &operator =(std::pair<V0, V1> v) // both g++ and msvc sort requires this (for insertion sort)
{
m_v0 = v.first;
m_v1 = v.second;
return *this;
}
CRefPair &operator =(const CRefPair &other) // required by g++ (for _GLIBCXX_MOVE)
{
m_v0 = other.m_v0;
m_v1 = other.m_v1;
return *this;
}
};
template <class V0, class V1>
inline bool operator <(std::pair<V0, V1> a, CRefPair<V0, V1> b) // required by both g++ and msvc
{
return a < std::pair<V0, V1>(b); // default pairwise lexicographical comparison
}
template <class V0, class V1>
inline bool operator <(CRefPair<V0, V1> a, std::pair<V0, V1> b) // required by both g++ and msvc
{
return std::pair<V0, V1>(a) < b; // default pairwise lexicographical comparison
}
template <class V0, class V1>
inline bool operator <(CRefPair<V0, V1> a, CRefPair<V0, V1> b) // required by both g++ and msvc
{
return std::pair<V0, V1>(a) < std::pair<V0, V1>(b); // default pairwise lexicographical comparison
}
namespace std {
template <class V0, class V1>
inline void swap(CRefPair<V0, V1> &a, CRefPair<V0, V1> &b)
{
a.swap(b);
}
} // ~std
template <class It0, class It1>
class CPairIterator : public std::random_access_iterator_tag {
public:
typedef typename std::iterator_traits<It0>::value_type value_type0;
typedef typename std::iterator_traits<It1>::value_type value_type1;
typedef std::pair<value_type0, value_type1> value_type;
typedef typename std::iterator_traits<It0>::difference_type difference_type;
typedef /*typename std::iterator_traits<It0>::distance_type*/difference_type distance_type; // no distance_type in g++, only in msvc
typedef typename std::iterator_traits<It0>::iterator_category iterator_category;
typedef CRefPair<value_type0, value_type1> reference;
typedef reference *pointer; // not so sure about this, probably can't be implemented in a meaningful way, won't be able to overload ->
// keep the iterator traits happy
protected:
It0 m_it0;
It1 m_it1;
public:
CPairIterator(const CPairIterator &r_other)
:m_it0(r_other.m_it0), m_it1(r_other.m_it1)
{}
CPairIterator(It0 it0 = It0(), It1 it1 = It1())
:m_it0(it0), m_it1(it1)
{}
reference operator *()
{
return reference(*m_it0, *m_it1);
}
value_type operator *() const
{
return value_type(*m_it0, *m_it1);
}
difference_type operator -(const CPairIterator &other) const
{
assert(m_it0 - other.m_it0 == m_it1 - other.m_it1);
// the iterators always need to have the same position
// (incomplete check but the best we can do without having also begin / end in either vector)
return m_it0 - other.m_it0;
}
bool operator ==(const CPairIterator &other) const
{
assert(m_it0 - other.m_it0 == m_it1 - other.m_it1);
return m_it0 == other.m_it0;
}
bool operator !=(const CPairIterator &other) const
{
return !(*this == other);
}
bool operator <(const CPairIterator &other) const
{
assert(m_it0 - other.m_it0 == m_it1 - other.m_it1);
return m_it0 < other.m_it0;
}
bool operator >=(const CPairIterator &other) const
{
return !(*this < other);
}
bool operator <=(const CPairIterator &other) const
{
return !(other < *this);
}
bool operator >(const CPairIterator &other) const
{
return other < *this;
}
CPairIterator operator +(distance_type d) const
{
return CPairIterator(m_it0 + d, m_it1 + d);
}
CPairIterator operator -(distance_type d) const
{
return *this + -d;
}
CPairIterator &operator +=(distance_type d)
{
return *this = *this + d;
}
CPairIterator &operator -=(distance_type d)
{
return *this = *this + -d;
}
CPairIterator &operator ++()
{
return *this += 1;
}
CPairIterator &operator --()
{
return *this += -1;
}
CPairIterator operator ++(int) // msvc sort actually needs this, g++ does not
{
CPairIterator old = *this;
++ (*this);
return old;
}
CPairIterator operator --(int)
{
CPairIterator old = *this;
-- (*this);
return old;
}
};
template <class It0, class It1>
inline CPairIterator<It0, It1> make_pair_iterator(It0 it0, It1 it1)
{
return CPairIterator<It0, It1>(it0, it1);
}
It is kind of rough around the edges, maybe I'm just bad at overloading the comparisons, but the amount of differences needed to support different implementations of std::sort makes me think the hackish solution might actually be more portable. But the sorting is much nicer:
struct CompareByFirst {
bool operator ()(std::pair<size_t, char> a, std::pair<size_t, char> b) const
{
return a.first < b.first;
}
};
std::vector<char> vv; // filled by values
std::vector<size_t> kv; // filled by keys
std::sort(make_pair_iterator(kv.begin(), vv.begin()),
make_pair_iterator(kv.end(), vv.end()), CompareByFirst());
// nice
And of course it gives the correct result.
Inspired by a comment by Mark Ransom, this is a horrible hack, and an example of how not to do it. I only wrote it for amusement and because I was wondering how complicated would it get. This is not an answer to my question, I will not use this. I just wanted to share a bizarre idea. Please, do not downvote.
Actually, ignoring multithreading, I believe this could be done:
template <class KeyType, class ValueVectorType>
struct MyKeyWrapper { // all is public to save getters
KeyType k;
bool operator <(const MyKeyWrapper &other) const { return k < other.k; }
};
template <class KeyType, class ValueVectorType>
struct ValueVectorSingleton { // all is public to save getters, but kv and vv should be only accessible by getters
static std::vector<MyKeyWrapper<KeyType, ValueVectorType> > *kv;
static ValueVectorType *vv;
static void StartSort(std::vector<MyKeyWrapper<KeyType, ValueVectorType> > &_kv, ValueVectorType &_vv)
{
assert(!kv && !vv); // can't sort two at once (if multithreading)
assert(_kv.size() == _vv.size());
kv = &_kv, vv = &_vv; // not an attempt of an atomic operation
}
static void EndSort()
{
kv = 0, vv = 0; // not an attempt of an atomic operation
}
};
template <class KeyType, class ValueVectorType>
std::vector<MyKeyWrapper<KeyType, ValueVectorType> >
*ValueVectorSingleton<KeyType, ValueVectorType>::kv = 0;
template <class KeyType, class ValueVectorType>
ValueVectorType *ValueVectorSingleton<KeyType, ValueVectorType>::vv = 0;
namespace std {
template <class KeyType, class ValueVectorType>
void swap(MyKeyWrapper<KeyType, ValueVectorType> &a,
MyKeyWrapper<KeyType, ValueVectorType> &b)
{
assert((ValueVectorSingleton<KeyType, ValueVectorType>::vv &&
ValueVectorSingleton<KeyType, ValueVectorType>::kv)); // if this triggers, someone forgot to call StartSort()
ValueVectorType &vv = *ValueVectorSingleton<KeyType, ValueVectorType>::vv;
std::vector<MyKeyWrapper<KeyType, ValueVectorType> > &kv =
*ValueVectorSingleton<KeyType, ValueVectorType>::kv;
size_t ai = &kv.front() - &a, bi = &kv.front() - &b; // get indices in key vector
std::swap(a, b); // swap keys
std::swap(vv[ai], vv[bi]); // and any associated values
}
} // ~std
And sorting as:
std::vector<char> vv; // filled by values
std::vector<MyKeyWrapper<size_t, std::vector<char> > > kv; // filled by keys, casted to MyKeyWrapper
ValueVectorSingleton<size_t, std::vector<char> >::StartSort(kv, vv);
std::sort(kv.begin(), kv.end());
ValueVectorSingleton<size_t, std::vector<char> >::EndSort();
// trick std::sort into using the custom std::swap which also swaps the other vectors
This is obviously very appalling, trivial to abuse in horrible ways, but arguably much shorter than the pair of iterators and probably similar in performance. And it actually works.
Note that swap() could be implemented inside ValueVectorSingleton and the one injected in the std namespace would just call it. That would avoid having to make vv and kv public. Also, the addresses of a and b could further be checked to make sure they are inside kv and not some other vector. Also, this is limited to sorting by values of only one vector (can't sort by corresponding values in both vectors at the same time). And the template parameters could be simply KeyType and ValueType, this was written in a hurry.
Here is a solution I once used to sort an array together with an array of indices (--maybe it is from somewhere over here?):
template <class iterator>
class IndexComparison
{
public:
IndexComparison (iterator const& _begin, iterator const& _end) :
begin (_begin),
end (_end)
{}
bool operator()(size_t a, size_t b) const
{
return *std::next(begin,a) < *std::next(begin,b);
}
private:
const iterator begin;
const iterator end;
};
Usage:
std::vector<int> values{5,2,5,1,9};
std::vector<size_t> indices(values.size());
std::iota(indices.begin(),indices.end(),0);
std::sort(indices.begin(),indices.end()
, IndexComparison<decltype(values.cbegin())>(values.cbegin(),values.cend()));
Afterwards, the integers in vector indices are permuted such that they correspond to increasing values in the vector values. It is easy to extend this from less-comparison to general comparison functions.
Next, in order to sort also the values, you can do another
std::sort(values.begin(),values.end());
using the same comparison function. This is the solution for the lazy ones. Of course, you can alternatively also use the sorted indices according to
auto temp=values;
for(size_t i=0;i<indices.size();++i)
{
values[i]=temp[indices[i]];
}
DEMO
EDIT: I just realized that the above sorts into the opposite direction than the one you were asking for.
I want to write my own algorithm (just a function really) that takes a range of iterators. If the iterators are from a map, I want to use the data (iterator->second) value. If the iterator is "normal" like a vector or list, I just want to use the dereferenced iterator value.
I think, value-getter idea is right here, but you can implement it without c++11 and without structs at all, only using functions:
template <typename T>
const T& get(const T& t)
{
return t;
}
template <typename T, typename V>
const V& get(const std::pair<T,V>& t)
{
return t.second;
}
int main()
{
std::vector<int> v = {1};
std::cout << get(*v.begin());
std::cout << "\n----\n";
std::map<int, std::string> m;
m.insert(std::make_pair(0, "sss"));
std::cout << get(*m.cbegin());
}
You can make a value-getter class that extracts the value you're interested in. Note that this approach doesn't work if you store pairs in any container (it transforms all pairs, whether in a map or not). I'd think it would be a much clearer approach to only accept "regular" iterators and let it be callers job to transform map iterators appropriately (as suggested in the comments to your question.)
template<typename T>
struct get {
static auto val(const T& t) -> const T&
{
return t;
}
};
template<typename U, typename V>
struct get<std::pair<U, V>> {
static auto val(const std::pair<U, V>& p) -> const V&
{
return p.second;
}
};
// use like
get<decltype(*iter)>::val(*iter);
Convenience function could look like:
template<class T>
auto getval(const T& t) -> decltype(get<T>::val(t))
{
return get<T>::val(t);
}
You can overload the function based on the input:
void foo(const std::vector<int>::iterator& it1, const std::vector<int>::iterator& it2)
{
//use *it
}
void foo(const std::map<int,int>::iterator& it1, const std::map<int,int>::iterator& it2)
{
//use it->second
}
Edit:
I think this is the closest you can get to what you want to achieve:
template <typename T, typename X>
void foo(T const& x, X const& y)
{
}
template <typename T, typename S>
void foo(const typename std::map<T,S>::iterator& x, const typename std::map<T,S>::iterator& y)
{
}
int main()
{
std::map<int,int> x;
std::vector<int> y;
foo(x.begin(), x.end()); //will call second version
foo(y.begin(), y.end()); //will call first version
}
A trait should do the trick. First the type-deducing helper:
template <typename Iter>
typename iter_value<Iter>::value_type & iter_deref(Iter it)
{
return iter_value<Iter>::deref(it);
}
All we need is something like this:
template <typename Iter>
class iter_value
{
template <typename T> struct aux
{
typedef T type;
static type & deref(Iter it) { return *it; }
};
template <typename U, typename V> struct aux<std::pair<U const, V>>
{
typedef V type;
static type & deref(Iter it) { return it->second; }
};
typedef typename std::iterator_traits<Iter>::value_type type;
public:
typedef typename aux<type>::type value_type;
static value_type & deref(Iter it)
{
return aux<type>::deref(it);
}
};
You can create a function that extracts the value out of the iterator. Then you can overload that based on the type of the iterator. You can use that function in your algorithm. Assuming a vector of ints and a map of string->int, it could look like this:
int getValue(const std::vector<int>::iterator& it)
{
return *it;
}
int getValue(const std::map<std::string, int>::iterator& it)
{
return it->second;
}
Then the algorithm can use the function getValue() to get a value from the iterator.
Hy there,
I'm trying to adapt an existing code to boost::variant. The idea is to use boost::variant for a heterogeneous vector. The problem is that the rest of the code use iterators to access the elements of the vector. Is there a way to use the boost::variant with iterators?
I've tried
typedef boost::variant<Foo, Bar> Variant;
std::vector<Variant> bag;
std::vector<Variant>::iterator it;
for(it= bag.begin(); it != bag.end(); ++it){
cout<<(*it)<<endl;
}
But it didn't work.
EDIT: Thank you for your help! But in my design, I need to get one element from the list and pass it around other parts of the code (and that can be nasty, as I'm using GSL). The idea of using an iterator is that I can pass the iterator to a function, and the function will operate on the return data from that specific element. I can't see how to do that using for_each. I need to do something similar to that:
for(it=list.begin(); it!=list.end();++it) {
for(it_2=list.begin(); it_2!=list.end();++it_2) {
if(it->property() != it_2->property()) {
result = operate(it,it_2);
}
}
}
Thanks!
Well of course there is. Dereferencing the iterators will naturally yield a boost::variant<...> reference or const-reference.
However it does mean that the rest of code should be variant-aware. And notably use the boost::static_visitor to execute operations on the variants.
EDIT:
Easy!
struct Printer: boost::static_visitor<>
{
template <class T>
void operator()(T const& t) const { std::cout << t << std::endl; }
};
std::for_each(bag.begin(), bag.end(), boost::apply_visitor(Printer());
Note how writing a visitor automatically yields a predicate for STL algorithms, miam!
Now, for the issue of the return value:
class WithReturn: boost::static_visitor<>
{
public:
WithReturn(int& result): mResult(result) {}
void operator()(Foo const& f) const { mResult += f.suprise(); }
void operator()(Bar const& b) const { mResult += b.another(); }
private:
int& mResult;
};
int result;
std::for_each(bag.begin(), bag.end(), boost::apply_visitor(WithReturn(result)));
EDIT 2:
It's easy, but indeed need a bit of coaching :)
First, we remark there are 2 different operations: != and operate
struct PropertyCompare: boost::static_visitor<bool>
{
template <class T, class U>
bool operator()(T const& lhs, U const& rhs)
{
return lhs.property() == rhs.property();
}
};
struct Operate: boost::static_visitor<result_type>
{
result_type operator()(Foo const& lhs, Foo const& rhs);
result_type operator()(Foo const& lhs, Bar const& rhs);
result_type operator()(Bar const& lhs, Bar const& rhs);
result_type operator()(Bar const& lhs, Foo const& rhs);
};
for(it=list.begin(); it!=list.end();++it) {
for(it_2=list.begin(); it_2!=list.end();++it_2) {
if( !boost::apply_visitor(PropertyCompare(), *it, *it_2) ) {
result = boost::apply_visitor(Operate(), *it, *it_2));
}
}
}
For each is not that good here, because of this if. It would work if you could somehow factor the if in operate though.
Also note that I pass not iterators but references.