Topic: operator->* for iterators
Author: dheld@codelogicconsulting.com ("David B. Held")
Date: Tue, 19 Nov 2002 23:44:06 +0000 (UTC) Raw View
Hendrik Schober wrote:
> [...]
> porting some code I came across the problem, that
> operator->* doesn't work for iterators. The code used
> an iterator into a vector and it used to compile fine.
> But on the new platform, a vector's iterator isn't a
> simple pointer, so the compiler barked.
> While changing
> it->*pMember = value;
> to
> (*it).*pMember = value;
> cured the problem, I wonder whether it is a good
> thing to have to obscure the code that way. To me it
> seems that the STL relies on the similarity of plain
> pointers and iterators. But writing generic code one
> would be forbidden to use the simpler syntax.
> So to me it seems that iterators should indeed
> overload this operator.
It would be nice, but it turns out to be expensive.
> I'm don't think, pointers to members are in wide use
> these days.
I disagree. I use them in quite a few places, and with the advent of
complex binders, I think they are being used more often, not less.
> (In fact, during the last five years I used them only once -- in the
> code which caused the trouble.) OTOH, to me this seems is a minor
> addition which is unlikely to break any existing code, so IMHO
> adding this operator to the iterator requirements would be a good thing.
>
> What do you think?
I ran across this issue with smart pointers. It turns out that the
result of p->*mf is a closure, which is not trivially implemented. That
is, you need to produce a callable entity with the arity of mf already
bound to p. It might be possible to harness boost::function (hopefully
soon to be std::function) to produce this operator, but I'm afraid that
it's also horribly inefficient for a small bit of syntactic sugar. On
the other hand, if we get native closures (which, ironically,
boost::function will probably prevent), then it could become very easy
to write such an operator, and possibly fairly efficient, as well.
Dave
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: leavings@attbi.com ("Paul Mensonides")
Date: Tue, 19 Nov 2002 23:46:06 +0000 (UTC) Raw View
"llewelly" <llewelly.@@xmission.dot.com> wrote in message
news:86n0o6x0bz.fsf@Zorthluthik.foo...
> SpamTrap@gmx.de ("Hendrik Schober") writes:
> Unfortunately, operator->* doesn't have that semantic. It is
> overloaded like any other binary operator. This doesn't prevent
> implementation of an operator->* that works for data pointers, but
> an operator->* that works for member function requires knowing the
> number of arguments of the member function(s) used with
> operator->*. A library implementor can't know that,
> and can't readily cover all posibilities.
Yes, it can. At least, up to a reasonable limit on the number of parameters
in a pointer-to-member-function type. Furthermore, this can be done
generically to make it easy to reuse.
Paul Mensonides
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: leavings@attbi.com ("Paul Mensonides")
Date: Wed, 20 Nov 2002 00:57:04 +0000 (UTC) Raw View
""David B. Held"" <dheld@codelogicconsulting.com> wrote in message
news:utlio0ftqt3o43@corp.supernews.com...
> I ran across this issue with smart pointers. It turns out that the
> result of p->*mf is a closure, which is not trivially implemented. That
> is, you need to produce a callable entity with the arity of mf already
> bound to p. It might be possible to harness boost::function (hopefully
> soon to be std::function) to produce this operator, but I'm afraid that
> it's also horribly inefficient for a small bit of syntactic sugar. On
> the other hand, if we get native closures (which, ironically,
> boost::function will probably prevent), then it could become very easy
> to write such an operator, and possibly fairly efficient, as well.
It's not that inefficient or difficult to generate the necessary closure
structures. I did this a while back when someone asked about it at Boost.
Usage ultimately comes down to something like this:
template<class T> class smart_ptr {
private:
T* m_ptr;
// ...
public:
template<class U> inline closure<U>::type operator->*(U mem) {
return make_closure(m_ptr, mem);
}
};
Really easy to use/reuse, and is fairly efficient.
Paul Mensonides
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: dheld@codelogicconsulting.com ("David B. Held")
Date: Wed, 20 Nov 2002 05:12:26 +0000 (UTC) Raw View
Paul Mensonides wrote:
> ""David B. Held"" wrote in message
> news:utlio0ftqt3o43@corp.supernews.com...
>
> [...]
> It's not that inefficient or difficult to generate the necessary
> closure structures. I did this a while back when someone asked about
> it at Boost.
I know. *I* asked about it! ;)
> Usage ultimately comes down to something like this:
>
> template class smart_ptr {
> private:
> T* m_ptr;
> // ...
> public:
> template inline closure_::type operator->*(U mem) {
> return make_closure(m_ptr, mem);
> }
> };
>
> Really easy to use/reuse, and is fairly efficient.
Well, you still have to create a closure object consisting of the object
pointer + member function pointer, then copy that, then call the real
operator->* on the copy. Compare that to just dereferencing the
iterator and calling operator.*. Also, the closure_::type is hardly
trivial. It basically has to reproduce the functionality of
boost::function. So at runtime, the cost might not be terribly high,
but at compile time, you get a lot of template parsing overhead just so
you can use operator->* instead of operator.*. And to be anal, a
user-defined operator->* doesn't work just like the builtin, since the
result of the builtin is an unnameable untyped callable entity, whereas,
you can store the closure returned by your definition.
Dave
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: leavings@attbi.com ("Paul Mensonides")
Date: Wed, 20 Nov 2002 18:58:00 +0000 (UTC) Raw View
""David B. Held"" <dheld@codelogicconsulting.com> wrote in message
news:utm28s3vitrh71@corp.supernews.com...
> > [...]
> > It's not that inefficient or difficult to generate the necessary
> > closure structures. I did this a while back when someone asked about
> > it at Boost.
>
> I know. *I* asked about it! ;)
Oops, sorry. :)
>
> > Really easy to use/reuse, and is fairly efficient.
>
> Well, you still have to create a closure object consisting of the object
> pointer + member function pointer, then copy that, then call the real
> operator->* on the copy.
POD-structure copy, with a small structure. Also, the copying can be elided
by the compiler, especially since the object is unnamed, and all the
functions are easily inlined.
> Compare that to just dereferencing the
> iterator and calling operator.*. Also, the closure_::type is hardly
> trivial.
Oh, it's pretty trivial. It's only purposes are to 1) move the overload set
outside of the class definition (i.e. for reuse), and 2) to handle
pointers-to-data-members.
> It basically has to reproduce the functionality of
> boost::function. So at runtime, the cost might not be terribly high,
> but at compile time, you get a lot of template parsing overhead just so
> you can use operator->* instead of operator.*.
Honestly, though, it isn't a *lot* of template parsing. Some, yes, but you
always pay for convenience at some point. In this case, the compile-time
difference (ignoring Boost.PP for the moment) is negligible, and the runtime
performance involves a copy of a POD-structure--no big deal.
> And to be anal, a
> user-defined operator->* doesn't work just like the builtin, since the
> result of the builtin is an unnameable untyped callable entity, whereas,
> you can store the closure returned by your definition.
Well, obviously you can prevent that from happening if you actually want to,
but that is part of the purpose of a closure. That is exactly what would
happen if a closure facility was built into the language itself.
To be *really* anal, on the other hand, such a mechanism cannot handle
variadic member functions, which the built-in operators can. Though I don't
consider that to be too big a deal. :)
Paul Mensonides
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: dheld@codelogicconsulting.com ("David B. Held")
Date: Thu, 21 Nov 2002 23:13:34 +0000 (UTC) Raw View
Paul Mensonides wrote:
> [...]
> POD-structure copy, with a small structure. Also, the copying can be
> elided by the compiler, especially since the object is unnamed, and
> all the functions are easily inlined.
You make it sound so cheap, and yet I know people who would complain
about even this cost.
> [...]
> Honestly, though, it isn't a *lot* of template parsing. Some, yes,
> but you always pay for convenience at some point. In this case, the
> compile-time difference (ignoring Boost.PP for the moment) is
> negligible, and the runtime performance involves a copy of a
> POD-structure--no big deal.
Ok, well here's the thing. I think it might be handy to define
operator->* for Loki::SmartPtr (that I'm working on). Could you
generate the closure type (with all the operator() overloads) using
boost::pp for me? I will probably incorporate it with a macro switch or
policy (as if it doesn't have enough already!). Or do you think it
would be better to use boost::function instead? Personally, I'd rather
not have the dependency, but if there is too much overlap, there's no
sense in duplication.
> [...]
> Well, obviously you can prevent that from happening if you actually
> want to, but that is part of the purpose of a closure. That is
> exactly what would happen if a closure facility was built into the
> language itself.
True. Which I still think would be useful, despite how handy
boost::function && boost::bind are.
> [...]
Dave
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: leavings@attbi.com ("Paul Mensonides")
Date: Fri, 22 Nov 2002 05:52:57 +0000 (UTC) Raw View
[Note to moderator - I'm trying to take this off the usenet group, but
David's address seems to be down, so sorry about the lack of topicality.]
""David B. Held"" <dheld@codelogicconsulting.com> wrote in message
news:utqov1ha5os6cf@corp.supernews.com...
> Ok, well here's the thing. I think it might be handy to define
> operator->* for Loki::SmartPtr (that I'm working on). Could you
> generate the closure type (with all the operator() overloads) using
> boost::pp for me? I will probably incorporate it with a macro switch or
> policy (as if it doesn't have enough already!).
Why would you want to have it conditioned on a macro or as a policy? It
doesn't harm anything if it isn't called.
David, please send me a valid email address, and I'll send you the code.
Paul Mensonides
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: SpamTrap@gmx.de ("Hendrik Schober")
Date: Sun, 17 Nov 2002 23:45:28 +0000 (UTC) Raw View
Hi,
porting some code I came across the problem, that
operator->* doesn't work for iterators. The code used
an iterator into a vector and it used to compile fine.
But on the new platform, a vector's iterator isn't a
simple pointer, so the compiler barked.
While changing
it->*pMember = value;
to
(*it).*pMember = value;
cured the problem, I wonder whether it is a good
thing to have to obscure the code that way. To me it
seems that the STL relies on the similarity of plain
pointers and iterators. But writing generic code one
would be forbidden to use the simpler syntax.
So to me it seems that iterators should indeed
overload this operator.
I'm don't think, pointers to members are in wide use
these days. (In fact, during the last five years I
used them only once -- in the code which caused the
trouble.) OTOH, to me this seems is a minor addition
which is unlikely to break any existing code, so IMHO
adding this operator to the iterator requirements
would be a good thing.
What do you think?
Regards,
Schobi
--
SpamTrap@gmx.de is never read
I'm hschober at gmx dot de
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: pjp@dinkumware.com ("P.J. Plauger")
Date: Mon, 18 Nov 2002 01:01:52 +0000 (UTC) Raw View
""Hendrik Schober"" <SpamTrap@gmx.de> wrote in message news:3dd7f26b_2@news.arcor-ip.de...
> porting some code I came across the problem, that
> operator->* doesn't work for iterators. The code used
> an iterator into a vector and it used to compile fine.
> But on the new platform, a vector's iterator isn't a
> simple pointer, so the compiler barked.
> While changing
> it->*pMember = value;
> to
> (*it).*pMember = value;
> cured the problem, I wonder whether it is a good
> thing to have to obscure the code that way. To me it
> seems that the STL relies on the similarity of plain
> pointers and iterators. But writing generic code one
> would be forbidden to use the simpler syntax.
> So to me it seems that iterators should indeed
> overload this operator.
>
> I'm don't think, pointers to members are in wide use
> these days. (In fact, during the last five years I
> used them only once -- in the code which caused the
> trouble.) OTOH, to me this seems is a minor addition
> which is unlikely to break any existing code, so IMHO
> adding this operator to the iterator requirements
> would be a good thing.
>
> What do you think?
They're already required by the C++ Standard. Some compilers
(such as VC++ V6.0) cannot tolerate an operator->() definition
in a class where it wouldn't make sense, so that's why you
won't find operator-> defined everywhere it should be.
P.J. Plauger
Dinkumware, Ltd.
http://www.dinkumware.com
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: SpamTrap@gmx.de ("Hendrik Schober")
Date: Mon, 18 Nov 2002 16:25:50 +0000 (UTC) Raw View
""P.J. Plauger"" <pjp@dinkumware.com> wrote:
> [...]
> They're already required by the C++ Standard. Some compilers
> (such as VC++ V6.0) cannot tolerate an operator->() definition
> in a class where it wouldn't make sense, so that's why you
> won't find operator-> defined everywhere it should be.
Only I was talking of 'operator->*()'.
> P.J. Plauger
Schobi
--
SpamTrap@gmx.de is never read
I'm HSchober at gmx dot de
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: llewelly.@@xmission.dot.com (llewelly)
Date: Mon, 18 Nov 2002 18:20:17 +0000 (UTC) Raw View
SpamTrap@gmx.de ("Hendrik Schober") writes:
> Hi,
>
> porting some code I came across the problem, that
> operator->* doesn't work for iterators. The code used
> an iterator into a vector and it used to compile fine.
> But on the new platform, a vector's iterator isn't a
> simple pointer, so the compiler barked.
> While changing
> it->*pMember = value;
> to
> (*it).*pMember = value;
A generic operator->*, which works for data mebers (but not member
functions), can be implemented along the lines of:
template<typename Member_Pointer_Type>
struct Get_Member_Type{};
template<typename Class_Type,typename Member_Type>
struct Get_Member_Type<Member_Type Class_Type::*>
{
typedef Class_Type Class;
typedef Member_Type Member;
};
template<typename Iterator,typename Member_Pointer_Type>
typename Get_Member_Type<Member_Pointer_Type>::Member& operator->*
(Iterator lhs,Member_Pointer_Type rhs)
{
return (*lhs).*rhs;
}
operator-> is genericly overloadable for iterators (and other
pointer-emulating classes) because of its interesting semantic -
the -> operator and the name on the right side are re-applied to
the object returned by the user-defined operator-> . This is
important because it means the writer of operator-> doesn't need
to know anything about the types of any member functions the
pointee might have.
Unfortunately, operator->* doesn't have that semantic. It is
overloaded like any other binary operator. This doesn't prevent
implementation of an operator->* that works for data pointers, but
an operator->* that works for member function requires knowing the
number of arguments of the member function(s) used with
operator->*. A library implementor can't know that,
and can't readily cover all posibilities.
> cured the problem, I wonder whether it is a good
> thing to have to obscure the code that way. To me it
> seems that the STL relies on the similarity of plain
> pointers and iterators. But writing generic code one
> would be forbidden to use the simpler syntax.
> So to me it seems that iterators should indeed
> overload this operator.
I agree with you. But in the current language, it wouldn't work well
for member function pointers.
>
> I'm don't think, pointers to members are in wide use
> these days. (In fact, during the last five years I
> used them only once -- in the code which caused the
> trouble.) OTOH, to me this seems is a minor addition
> which is unlikely to break any existing code, so IMHO
> adding this operator to the iterator requirements
> would be a good thing.
>
> What do you think?
I think a member overload of operator->* with no arguments, or a
non-member overload of operator->* with only one argument, (both
ill-formed in the current standard, which defines ->* as binary)
should be defined along the lines of current operator-> .
But I doubt pointers to members are used frequently. Likely they
are so seldom used that the effort required to add the extention I
mentioned above (I can think of at least one odd subtlety that
might be hard to handle) would be better expended elsewhere.
[snip]
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]