function template problem

J

John Harrison

This might be a compiler problem or it might be some subtlety of the
language I don't understand.

I'm writing an iterator and I want to write a version of std::distance
specially for my iterator. Here's some code (highly reduced of course). The
issue is how the return type of std::distance should be written.

#include <iostream>
#include <cstddef>
#include <iterator>

template <class T>
class Iter
{
public:
typedef std::input_iterator_tag iterator_category;
typedef T value_type;
typedef T& reference;
typedef T* pointer;
typedef std::size_t size_type;
typedef std::ptrdiff_t difference_type;
bool operator==(Iter rhs) const { return true; }
bool operator!=(Iter rhs) const { return false; }
Iter& operator++() { return *this; }
Iter operator++(int) { return *this; }
};

namespace std
{
template <class T>
typename std::iterator_traits<Iter<T> >::distance_type /* return type 1 */
// std::ptrdiff_t /* return type 2 */
distance(Iter<T> first, Iter<T> last)
{
std::cout << "success\n";
return 0;
}
}

int main()
{
std::distance(Iter<int>(), Iter<int>());
}

On MSVC++ 7.1 this prints "success" proving that my version of std::distance
has been called. On gcc 3.3.1 it does not. However if I change the return
type of my version std::distance to std::ptrdiff_t, then gcc 3.3.1 prints
"success" as well.

I was pretty much sure this was a gcc compiler bug but I thought I'd test
with Comeau C++ online, from what I've been able to tell Comeau works the
same as gcc, so now I'm not so sure.

Anyone able to tell me what's going on?

John
 
S

Siemel Naran

This might be a compiler problem or it might be some subtlety of the
language I don't understand.

I'm writing an iterator and I want to write a version of std::distance
specially for my iterator. Here's some code (highly reduced of course). The
issue is how the return type of std::distance should be written.

#include <iostream>
#include <cstddef>
#include <iterator>

template <class T>
class Iter
{
public:
typedef std::input_iterator_tag iterator_category;
typedef T value_type;
typedef T& reference;
typedef T* pointer;
typedef std::size_t size_type;
typedef std::ptrdiff_t difference_type;
bool operator==(Iter rhs) const { return true; }
bool operator!=(Iter rhs) const { return false; }
Iter& operator++() { return *this; }
Iter operator++(int) { return *this; }
};

namespace std
{
template <class T>
typename std::iterator_traits<Iter<T> >::distance_type /* return type 1 */
// std::ptrdiff_t /* return type 2 */
distance(Iter<T> first, Iter<T> last)
{
std::cout << "success\n";
return 0;
}
}

int main()
{
std::distance(Iter<int>(), Iter<int>());
}

On MSVC++ 7.1 this prints "success" proving that my version of std::distance
has been called. On gcc 3.3.1 it does not. However if I change the return
type of my version std::distance to std::ptrdiff_t, then gcc 3.3.1 prints
"success" as well.

MSVC 7 is right.

As an aside, I think you can define function distance in the same namespace
as class Iter. Koening lookup ensures that a call distance(iter1, iter2)
finds distance in the namespace where iter1 and iter2 live, and then in the
current namespace. But of course, people may write std::distance(...) which
forces the use of the function in the std namespace. So what you have still
seems a good idea.
I was pretty much sure this was a gcc compiler bug but I thought I'd test
with Comeau C++ online, from what I've been able to tell Comeau works the
same as gcc, so now I'm not so sure.

Anyone able to tell me what's going on?

There is a g++ newsgroup out there. Might be a bug.
 
R

Rob Williscroft

John Harrison wrote in in
comp.lang.c++:
This might be a compiler problem or it might be some subtlety of the
language I don't understand.
typedef std::ptrdiff_t difference_type;

template <class T>
typename std::iterator_traits<Iter<T> >::distance_type /* return type
Anyone able to tell me what's going on?

SFINAE:

template<class T> struct iterator_traits<T*> {
typedef ptrdiff_t difference_type;
typedef T value_type;
typedef T* pointer;
typedef T& reference;
typedef random_access_iterator_tag iterator_category;
};

There is no distance_type, change to difference_type.


Rob.
 
J

John Harrison

Rob Williscroft said:
John Harrison wrote in in
comp.lang.c++:




SFINAE:

template<class T> struct iterator_traits<T*> {
typedef ptrdiff_t difference_type;
typedef T value_type;
typedef T* pointer;
typedef T& reference;
typedef random_access_iterator_tag iterator_category;
};

There is no distance_type, change to difference_type.

Aarrgh!! MSVC++ has distance_type for backwards compatibility.

Thanks, and well spotted, everything works now.

john
 

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

Forum statistics

Threads
473,770
Messages
2,569,583
Members
45,072
Latest member
trafficcone

Latest Threads

Top