C++Talk.NET Forum Index C++Talk.NET
C++ language newsgroups
 
Archives   FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

work round for std::distance's long arm.

 
Post new topic   Reply to topic    C++Talk.NET Forum Index -> C++ Language (Moderated)
View previous topic :: View next topic  
Author Message
Louis Lavery
Guest





PostPosted: Fri Aug 18, 2006 6:08 pm    Post subject: work round for std::distance's long arm. Reply with quote



Without the nested typedefs the following fails to compile
under vc7 and gcc 3.2.

/* distance.cpp */
#include <iterator>
#include <list>

namespace user
{
template<typename Iter,typename Dist> struct Cursor
{
#if 0
typedef void iterator_category;
typedef void difference_type;
typedef void value_type;
typedef void reference;
typedef void pointer;
#endif
};

template<typename Iter,typename Dist>
Dist distance(
Cursor<Iter,Dist> const&,
Cursor<Iter,Dist> const&)
{
return 0;
}
}

int main()
{
user::Cursor<std::list<int>::iterator,int> cur;

distance(cur,cur); // XXX

return 0;
}
/* distance.cpp end */

Because Cursor's instantiated with an iterator from std,
I guess what happens (at XXX) is the compiler looks in
namespace std and sees something like...

template<class Iter>
typename iterator_traits<Iter>::difference_type
distance<Iter,Iter) {...}

....and so needs to instantiate iterator_traits<Cursor> to get
the return type. But the default iterator_traits requires its
parameter to have nested typedefs for iterator_category etc.
Have I got that right?

This being the case, what's the best work round?

I know I can use void typedefs as above but that adds noise.

Is there a better way, other than not using the name distance?

Thanks, Louis.

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Back to top
Greg Herlihy
Guest





PostPosted: Fri Aug 18, 2006 9:45 pm    Post subject: Re: work round for std::distance's long arm. Reply with quote



Louis Lavery wrote:
Quote:
Without the nested typedefs the following fails to compile
under vc7 and gcc 3.2.

/* distance.cpp */
#include <iterator
#include <list

namespace user
{
template<typename Iter,typename Dist> struct Cursor
{
#if 0
typedef void iterator_category;
typedef void difference_type;
typedef void value_type;
typedef void reference;
typedef void pointer;
#endif
};

template<typename Iter,typename Dist
Dist distance(
Cursor<Iter,Dist> const&,
Cursor<Iter,Dist> const&)
{
return 0;
}
}

int main()
{
user::Cursor<std::list<int>::iterator,int> cur;

distance(cur,cur); // XXX

return 0;
}
/* distance.cpp end */

Because Cursor's instantiated with an iterator from std,
I guess what happens (at XXX) is the compiler looks in
namespace std and sees something like...

template<class Iter
typename iterator_traits<Iter>::difference_type
distance<Iter,Iter) {...}

...and so needs to instantiate iterator_traits<Cursor> to get
the return type. But the default iterator_traits requires its
parameter to have nested typedefs for iterator_category etc.
Have I got that right?

The distance() function call does indeed call std::distance(). However,
iterator_traits is not instantiated in order to find std::distance's
return type (the compiler can figure that out without instantiating
iterator_traits). Instead it is the implementation of std::distance()
that relies on the iterators' nested typedefs when figuring out the
best way to calculate the distance between them.

Quote:
This being the case, what's the best work round?

If the program intends to call std::distance(), then there is no
workaround other to pass iterator types of the kind that
std::distance() expects. On the other hand, if this program is calling
std::distance() by mistake and really intends to be calling
user::distance(), then the function call has to be more explicit:

user::distance( cur, cur );

Quote:
I know I can use void typedefs as above but that adds noise.

The typedefs may be "noise" for a program calling user::distance() -
but are a prerequisite for one (such as this program in its current
form) calling std::distance().

Greg


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Back to top
dasjotre
Guest





PostPosted: Fri Aug 18, 2006 10:30 pm    Post subject: Re: work round for std::distance's long arm. Reply with quote



Louis Lavery wrote:
Quote:
Without the nested typedefs the following fails to compile
under vc7 and gcc 3.2.

/* distance.cpp */
#include <iterator
#include <list

namespace user
{
template<typename Iter,typename Dist> struct Cursor
{
#if 0
typedef void iterator_category;
typedef void difference_type;
typedef void value_type;
typedef void reference;
typedef void pointer;
#endif
};

template<typename Iter,typename Dist
Dist distance(
Cursor<Iter,Dist> const&,
Cursor<Iter,Dist> const&)
{
return 0;
}
}

int main()
{
user::Cursor<std::list<int>::iterator,int> cur;

distance(cur,cur); // XXX

std::distance uses iterator traits which need the
typedefs, user::distance does not, don't you mean
user::distance(cur, cur) ?

Quote:
return 0;
}
/* distance.cpp end */

Because Cursor's instantiated with an iterator from std,
I guess what happens (at XXX) is the compiler looks in
namespace std and sees something like...

template<class Iter
typename iterator_traits<Iter>::difference_type
distance<Iter,Iter) {...}


It is not clear how the compiler finds std::distance
in your example. I suppose there is a 'using' directive
somewhere.

Quote:
...and so needs to instantiate iterator_traits<Cursor> to get
the return type. But the default iterator_traits requires its
parameter to have nested typedefs for iterator_category etc.
Have I got that right?

This being the case, what's the best work round?


specify the namespace you want to use, i.e. user::distance.

Quote:
I know I can use void typedefs as above but that adds noise.

Is there a better way, other than not using the name distance?

Thanks, Louis.


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Back to top
Radu
Guest





PostPosted: Fri Aug 18, 2006 10:32 pm    Post subject: Re: work round for std::distance's long arm. Reply with quote

Louis Lavery wrote:
Quote:
Without the nested typedefs the following fails to compile
under vc7 and gcc 3.2.

/* distance.cpp */
#include <iterator
#include <list

namespace user
{
template<typename Iter,typename Dist> struct Cursor
{
#if 0
typedef void iterator_category;
typedef void difference_type;
typedef void value_type;
typedef void reference;
typedef void pointer;
#endif
};

template<typename Iter,typename Dist
Dist distance(
Cursor<Iter,Dist> const&,
Cursor<Iter,Dist> const&)
{
return 0;
}
}

int main()
{
user::Cursor<std::list<int>::iterator,int> cur;

distance(cur,cur); // XXX

return 0;
}
/* distance.cpp end */

Because Cursor's instantiated with an iterator from std,
I guess what happens (at XXX) is the compiler looks in
namespace std and sees something like...

template<class Iter
typename iterator_traits<Iter>::difference_type
distance<Iter,Iter) {...}

...and so needs to instantiate iterator_traits<Cursor> to get
the return type. But the default iterator_traits requires its
parameter to have nested typedefs for iterator_category etc.
Have I got that right?

That's correct. For example:
std::iterator_traits<_Iter>::iterator_category is attempting to use
_Iter=user::Cursor<std::list<int>::_Iterator<true>,int>.

Quote:

This being the case, what's the best work round?

I know I can use void typedefs as above but that adds noise.

Is there a better way, other than not using the name distance?

Thanks, Louis.

Any particular reason to not use:
user::distance(cur,cur);
?

Cheers,
Radu


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Back to top
Carl Barron
Guest





PostPosted: Sat Aug 19, 2006 1:52 am    Post subject: Re: work round for std::distance's long arm. Reply with quote

Louis Lavery <Louis (AT) laver (DOT) demon.co.uk> wrote:

Quote:
Without the nested typedefs the following fails to compile
under vc7 and gcc 3.2.

/* distance.cpp */
#include <iterator
#include <list

namespace user
{
template<typename Iter,typename Dist> struct Cursor
{
#if 0
typedef void iterator_category;
typedef void difference_type;
typedef void value_type;
typedef void reference;
typedef void pointer;
#endif
};

template<typename Iter,typename Dist
Dist distance(
Cursor<Iter,Dist> const&,
Cursor<Iter,Dist> const&)
{
return 0;
}

I'd bet that

std::distance immediately calls an internal function with another
argument solely to provide overloading based on the iterator_category
and this assumes that iterator_category is one of the members of the
iterator tags hierarchy, which void is not. This would allow fast
computation of distance for a random access iterator, and a slower
version for every other one that is readable.

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Back to top
Louis Lavery
Guest





PostPosted: Sat Aug 19, 2006 7:32 pm    Post subject: Re: work round for std::distance's long arm. Reply with quote

Greg Herlihy wrote:
Quote:
Louis Lavery wrote:

Without the nested typedefs the following fails to compile
under vc7 and gcc 3.2.

/* distance.cpp */
#include <iterator
#include <list

namespace user
{
template<typename Iter,typename Dist> struct Cursor
{
#if 0
typedef void iterator_category;
typedef void difference_type;
typedef void value_type;
typedef void reference;
typedef void pointer;
#endif
};

template<typename Iter,typename Dist
Dist distance(
Cursor<Iter,Dist> const&,
Cursor<Iter,Dist> const&)
{
return 0;
}
}

int main()
{
user::Cursor<std::list<int>::iterator,int> cur;

distance(cur,cur); // XXX

return 0;
}
/* distance.cpp end */

Because Cursor's instantiated with an iterator from std,
I guess what happens (at XXX) is the compiler looks in
namespace std and sees something like...

template<class Iter
typename iterator_traits<Iter>::difference_type
distance<Iter,Iter) {...}

...and so needs to instantiate iterator_traits<Cursor> to get
the return type. But the default iterator_traits requires its
parameter to have nested typedefs for iterator_category etc.
Have I got that right?


The distance() function call does indeed call std::distance().

Actually it doesn't call any thing as the code doesn't compile,
as I say in the first line of my post.

When the void typedefs are exposed, and it does compile, it calls
user:distance() as expected.

However,
Quote:
iterator_traits is not instantiated in order to find std::distance's
return type (the compiler can figure that out without instantiating
iterator_traits).

Yes it is (no it can't).

It has to instantiate iterator_traits, with Iter == Cursor, in
order to check that what is actually being returned is convertible
to difference_type (which is the function's return type).

Louis.



[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Back to top
David Abrahams
Guest





PostPosted: Sat Aug 19, 2006 8:05 pm    Post subject: Re: work round for std::distance's long arm. Reply with quote

Louis Lavery <Louis (AT) laver (DOT) demon.co.uk> writes:

Quote:
Without the nested typedefs the following fails to compile
under vc7 and gcc 3.2.

/* distance.cpp */
#include <iterator
#include <list

namespace user
{
template<typename Iter,typename Dist> struct Cursor
{
#if 0
typedef void iterator_category;
typedef void difference_type;
typedef void value_type;
typedef void reference;
typedef void pointer;
#endif
};

template<typename Iter,typename Dist
Dist distance(
Cursor<Iter,Dist> const&,
Cursor<Iter,Dist> const&)
{
return 0;
}
}

int main()
{
user::Cursor<std::list<int>::iterator,int> cur;

distance(cur,cur); // XXX

return 0;
}
/* distance.cpp end */

Because Cursor's instantiated with an iterator from std,
I guess what happens (at XXX) is the compiler looks in
namespace std

Yes, due to argument-dependent lookup. Because
std::list<int>::iterator is a class in namespace std, std becomes an
associated namespace of the argument, and the signature of that
function is considered during lookup.

Quote:
and sees something like...

template<class Iter
typename iterator_traits<Iter>::difference_type
distance<Iter,Iter) {...}

...and so needs to instantiate iterator_traits<Cursor> to get
the return type. But the default iterator_traits requires its
parameter to have nested typedefs for iterator_category etc.
Have I got that right?

Exactly.

Quote:
This being the case, what's the best work round?

Explicit qualification:

user::distance(cur,cur)

Of course, if your real case is a generic function in which the call
to distance is supposed to be a customization point, you'll have to
use a different dispatch method to avoid argument-dependent lookup.
Today there are few good alternatives.

Quote:
I know I can use void typedefs as above but that adds noise.

Is there a better way, other than not using the name distance?

Unfortunately not.

--
Dave Abrahams
Boost Consulting
www.boost-consulting.com

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Back to top
kanze
Guest





PostPosted: Mon Aug 21, 2006 4:32 pm    Post subject: Re: work round for std::distance's long arm. Reply with quote

David Abrahams wrote:
Quote:
Louis Lavery <Louis (AT) laver (DOT) demon.co.uk> writes:

Without the nested typedefs the following fails to compile
under vc7 and gcc 3.2.

/* distance.cpp */
#include <iterator
#include <list

namespace user
{
template<typename Iter,typename Dist> struct Cursor
{
};

template<typename Iter,typename Dist
Dist distance(
Cursor<Iter,Dist> const&,
Cursor<Iter,Dist> const&)
{
return 0;
}
}

int main()
{
user::Cursor<std::list<int>::iterator,int> cur;

distance(cur,cur); // XXX

return 0;
}
/* distance.cpp end */

Because Cursor's instantiated with an iterator from std, I
guess what happens (at XXX) is the compiler looks in
namespace std

Yes, due to argument-dependent lookup. Because
std::list<int>::iterator is a class in namespace std, std
becomes an associated namespace of the argument, and the
signature of that function is considered during lookup.

and sees something like...

template<class Iter
typename iterator_traits<Iter>::difference_type
distance<Iter,Iter) {...}

...and so needs to instantiate iterator_traits<Cursor> to
get the return type. But the default iterator_traits
requires its parameter to have nested typedefs for
iterator_category etc. Have I got that right?

Exactly.

But why doesn't SFINAE kick in, and eliminate std::distance from
consideration. Substituting
Cursor< std::list< int >::iterator, int >
for InputIterator in
template< typename InputIterator >
typename iterator_traits< InputIterator >::difference_type
distance( InputIterator first, InputIterator last ) ;
should result in a substitution failure, shouldn't it? Or does
the additional "indirection" (the fact that the typedef which
fails is in iterator_traits, and not in the function declaration
itself) block this?

--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Back to top
Howard Hinnant
Guest





PostPosted: Mon Aug 21, 2006 7:14 pm    Post subject: Re: work round for std::distance's long arm. Reply with quote

In article <1156153109.298765.179160 (AT) m73g2000cwd (DOT) googlegroups.com>,
"kanze" <kanze@gabi-soft.fr> wrote:

Quote:
David Abrahams wrote:
Louis Lavery <Louis (AT) laver (DOT) demon.co.uk> writes:

Without the nested typedefs the following fails to compile
under vc7 and gcc 3.2.

/* distance.cpp */
#include <iterator
#include <list

namespace user
{
template<typename Iter,typename Dist> struct Cursor
{
};

template<typename Iter,typename Dist
Dist distance(
Cursor<Iter,Dist> const&,
Cursor<Iter,Dist> const&)
{
return 0;
}
}

int main()
{
user::Cursor<std::list<int>::iterator,int> cur;

distance(cur,cur); // XXX

return 0;
}
/* distance.cpp end */

Because Cursor's instantiated with an iterator from std, I
guess what happens (at XXX) is the compiler looks in
namespace std

Yes, due to argument-dependent lookup. Because
std::list<int>::iterator is a class in namespace std, std
becomes an associated namespace of the argument, and the
signature of that function is considered during lookup.

and sees something like...

template<class Iter
typename iterator_traits<Iter>::difference_type
distance<Iter,Iter) {...}

...and so needs to instantiate iterator_traits<Cursor> to
get the return type. But the default iterator_traits
requires its parameter to have nested typedefs for
iterator_category etc. Have I got that right?

Exactly.

But why doesn't SFINAE kick in, and eliminate std::distance from
consideration. Substituting
Cursor< std::list< int >::iterator, int
for InputIterator in
template< typename InputIterator
typename iterator_traits< InputIterator >::difference_type
distance( InputIterator first, InputIterator last ) ;
should result in a substitution failure, shouldn't it? Or does
the additional "indirection" (the fact that the typedef which
fails is in iterator_traits, and not in the function declaration
itself) block this?

Yes, exactly. If we redefined iterator_traits<Iter> to be an empty
class unless Iter is a pointer, or Iter is a class containing a nested
type iterator_category which is convertible to one of the
std::iterator_tags (all doable in C++03), then SFINAE would kick in.

It is my hope that this problem will be fixed in C++0X, either by
concepts, or by an improved iterator_traits as described above.

-Howard

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Back to top
Lucian Radu Teodorescu
Guest





PostPosted: Wed Aug 23, 2006 11:28 pm    Post subject: Re: work round for std::distance's long arm. Reply with quote

{ this is overquoted. it's been let in rather than rejected hoping that
whoever answers it will trim it down; we've seen enough copies of the
original message. thanks. -mod }

David Abrahams wrote:
Quote:
Louis Lavery <Louis (AT) laver (DOT) demon.co.uk> writes:

Without the nested typedefs the following fails to compile
under vc7 and gcc 3.2.

/* distance.cpp */
#include <iterator
#include <list

namespace user
{
template<typename Iter,typename Dist> struct Cursor
{
#if 0
typedef void iterator_category;
typedef void difference_type;
typedef void value_type;
typedef void reference;
typedef void pointer;
#endif
};

template<typename Iter,typename Dist
Dist distance(
Cursor<Iter,Dist> const&,
Cursor<Iter,Dist> const&)
{
return 0;
}
}

int main()
{
user::Cursor<std::list<int>::iterator,int> cur;

distance(cur,cur); // XXX

return 0;
}
/* distance.cpp end */

Because Cursor's instantiated with an iterator from std,
I guess what happens (at XXX) is the compiler looks in
namespace std

Yes, due to argument-dependent lookup. Because
std::list<int>::iterator is a class in namespace std, std becomes an
associated namespace of the argument, and the signature of that
function is considered during lookup.


I still don't get it why user::distance() isn't considered during
lookup. Could you please point out the reason for this?

Thank you


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Back to top
David Abrahams
Guest





PostPosted: Thu Aug 24, 2006 2:13 am    Post subject: Re: work round for std::distance's long arm. Reply with quote

"Lucian Radu Teodorescu" <Luc.Teodorescu (AT) gmail (DOT) com> writes:

Quote:
David Abrahams wrote:
Louis Lavery <Louis (AT) laver (DOT) demon.co.uk> writes:

Because Cursor's instantiated with an iterator from std,
I guess what happens (at XXX) is the compiler looks in
namespace std

Yes, due to argument-dependent lookup. Because
std::list<int>::iterator is a class in namespace std, std becomes an
associated namespace of the argument, and the signature of that
function is considered during lookup.


I still don't get it why user::distance() isn't considered during
lookup. Could you please point out the reason for this?

It is considered. Due to ADL, it is not the only thing considered,
though. The consideration of std::distance is what causes the error,
and the error is not a substitution failure that falls under the
purview of SFINAE.

--
Dave Abrahams
Boost Consulting
www.boost-consulting.com

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Back to top
Display posts from previous:   
Post new topic   Reply to topic    C++Talk.NET Forum Index -> C++ Language (Moderated) All times are GMT
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2006 phpBB Group
SEO toolkit © 2004-2006 webmedic.