 |
C++Talk.NET C++ language newsgroups
|
| View previous topic :: View next topic |
| Author |
Message |
Louis Lavery Guest
|
Posted: Fri Aug 18, 2006 6:08 pm Post subject: work round for std::distance's long arm. |
|
|
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
|
Posted: Fri Aug 18, 2006 9:45 pm Post subject: Re: work round for std::distance's long arm. |
|
|
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
|
Posted: Fri Aug 18, 2006 10:30 pm Post subject: Re: work round for std::distance's long arm. |
|
|
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
|
Posted: Fri Aug 18, 2006 10:32 pm Post subject: Re: work round for std::distance's long arm. |
|
|
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
|
Posted: Sat Aug 19, 2006 1:52 am Post subject: Re: work round for std::distance's long arm. |
|
|
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
|
Posted: Sat Aug 19, 2006 7:32 pm Post subject: Re: work round for std::distance's long arm. |
|
|
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
|
Posted: Sat Aug 19, 2006 8:05 pm Post subject: Re: work round for std::distance's long arm. |
|
|
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
|
Posted: Mon Aug 21, 2006 4:32 pm Post subject: Re: work round for std::distance's long arm. |
|
|
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
|
Posted: Mon Aug 21, 2006 7:14 pm Post subject: Re: work round for std::distance's long arm. |
|
|
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
|
Posted: Wed Aug 23, 2006 11:28 pm Post subject: Re: work round for std::distance's long arm. |
|
|
{ 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
|
Posted: Thu Aug 24, 2006 2:13 am Post subject: Re: work round for std::distance's long arm. |
|
|
"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 |
|
 |
|
|
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
|
|