Neil Kirk
Neil Kirk

Reputation: 21793

Comparing two iterators of a different type in a template function

No C++11 or Boost :(

I have a function with the following signature.

template<class INPUT_ITR, class OUTPUT_ITR>
void DoWork(const INPUT_ITR in_it, const INPUT_ITR in_it_end, OUTPUT_ITR out_it, OUTPUT_ITR out_it_end, CONTEXT_DATA)

Normally some complex processing takes place between the input and output.. but sometimes a no-op is required, and the data is simply copied. The function supports in-place operations if the input and output data types are the same. So I have this code.

    if (NoOp)
    {
        if (in_it != out_it)
        {
            copy(in_it, in_it_end, out_it);
        }
    }

If an in-place operation has been requested (the iterator check), there is no need to copy any data.

This has worked fine until I call the function with iterators to different data types (int32 to int64 for example). Then it complains about the iterator check because they are incompatible types.

error C2679: binary '!=' : no operator found which takes a right-hand operand of type 'std::_Vector_iterator<std::_Vector_val<std::_Simple_types<unsigned __int64>>>

This has left me a bit stumped. Is there an easy way to perform this check if the data types are the same, but simply perform the copy if they are different types?

Thanks

Upvotes: 1

Views: 170

Answers (3)

Mike Seymour
Mike Seymour

Reputation: 254531

You can extract the test into a pair of templates; one for matching types, one for non-matching types.

template <class T1, class T2>
bool same(T1 const &, T2 const &) {return false;}

template <class T>
bool same(T const & a, T const & b) {return a == b;} 

Beware that this can give confusing results when used with types that you'd expect to be comparable. In C++11 (or with Boost, or a lot of tedious mucking around with templates) you could extend this to compare different types when possible; but that's beyond what you need here.

Also, note that you're relying on formally undefined behaviour, since iterators over different underlying sequences aren't required to be comparable. There is no way to tell from the iterators themselves whether this is the case.

Upvotes: 4

Jesse Good
Jesse Good

Reputation: 52365

You could use std::iterator_traits and a custom is_same type trait since you don't have c++11:

template<class T, class U>
struct is_same
{
   static const bool value = false;
};

template<class T>
struct is_same<T, T>
{
   static const bool value = true;
};

if(!is_same<typename std::iterator_traits<INPUT_ITR>::value_type, 
            typename std::iterator_traits<OUTPUT_ITR>::value_type>::value)
{
    copy(...);
}

Upvotes: 0

Neil Kirk
Neil Kirk

Reputation: 21793

I came up with a workaround. Any better suggestions welcome.

Overload the function to provide an in-place version. It's up to the user to request in-place now (in-place using the old function will perform the redundant copy in case of no op).

template<class ITR>
void DoWork(const ITR it, const ITR it_end, CONTEXT_DATA)
{
    if (! NoOp)
    {
        DoWork(it, it_end, it, it_end, sSourceSpec, sDestSpec);
    }
}

Upvotes: 1

Related Questions