Groups | Search | Server Info | Keyboard shortcuts | Login | Register
| Message-ID | <4b41ec09-4b4f-46ac-9334-7aa41384732a@googlegroups.com> (permalink) |
|---|---|
| Newsgroups | comp.std.c++ |
| From | via.usov@googlemail.com |
| Subject | object and pointer-to-member closure: trivial intent, arcane implementation |
| Organization | unknown |
| Date | 2015-02-28 14:59 -0600 |
Apologies if this has been posted before. If there is a similar topic,
please point me to it.
Consider the following.
#include <functional>
struct A {};
struct B {};
struct C {};
void f(std::function<void(A, B, C)> g) { g(A(), B(), C()); }
void g(A, B, C) {}
Now, I can do this:
f(g); // (*)
If I further define
struct D
{
void g(A, B, C) {}
};
I could naively hope that the following trivial modification of (*) would
work:
D d;
f(d.g);
It does not (more on that later). The intent, I believe, is fairly obvious:
I want to pass the closure of d with D::g() to f().
I can achieve the goal via this:
D d;
f([&d](A a, B, C c){d.g(a, b, c);});
I dislike this, however, because it is quite verbose and violates the DRY
principle quite blatantly.
Another possible option is:
D d;
f(std::bind(&D::g, d, std::placeholders::_1, std::placeholders::_2,
std::placeholders::_3));
The problem with this other option is that it has taken me a few minutes of
trial, error and intense staring at the docs. And I had to read some more
docs just to understand whether this syntax would be functionally
equivalent to the previous option if g() were declared virtual and D were a
part of some class hierarchy. Let's face it, that thing is way too
complicated given the simplicity of the need. And DRY is still being
violated, because I need to spell out the name D and use three place
holders.
Another problem is that now, having at least two different ways of doing
what I need, I would like to understand the tradeoffs involved. Which I
cannot, because both approaches eventually utilize something that is
expressly left unspecified by the standard.
At which point a sane person would say: if both methods invoke some
compiler magic, then perhaps it is the compiler that should figure out
which magic works better, and so it should magically transform the naive
f(d.g) into the appropriate implementation. Which it cannot do, because
f(d.g) is expressly forbidden by the standard. Quoting draft n3797, 5.2.5.4:
-- Otherwise, if E1.E2 refers to a non-static member function and the type
of E2 is "function of parameter-type-list cv ref-qualifieropt returning T",
then E1.E2 is a prvalue. The expression designates a non-static member
function. The expression can be used only as the left-hand operand of a
member function call (9.3).
[end quote]
So d.g is quite explicitly forbidden unless followed by a function call
operator.
f(&d.g) does not work either, because the d.g is still not followed by a
function call operator, and also because d.g is a prvalue, also specified
by 5.2.5.4, and clause 5.3.1.3 (that specifies the semantics of &) works
with either lvalues or qualified IDs, i.e., D::g, not d.g.
I understand why such use was forbidden prior to C++11: there was no
closure support built into the language. But it exists now. As far as I can
tell, the compiler IN PRINCIPLE, upon encountering d.g (or pd->g, where pd
is a pointer to D) and understanding that g is a non-static member function
(which it has to do anyway, if only to handle the function call operator
that must follow, or emit an error message otherwise) could more or less
mechanically transform that code into the code similar to what I wrote
above (or do something much smarter).
Is there any fundamental reason why this could not be done? I realize that
there are complications related to overloaded and template member
functions; but that same sort of complications is also dealt with when the
address of a non-member function is taken.
Would that contradict the standard in some major way?
Thanks in advance.
--
[ comp.std.c++ is moderated. To submit articles, try posting with your ]
[ newsreader. If that fails, use mailto:std-cpp-submit@vandevoorde.com ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Back to comp.std.c++ | Previous | Next — Next in thread | Find similar
object and pointer-to-member closure: trivial intent, arcane implementation via.usov@googlemail.com - 2015-02-28 14:59 -0600
Re: object and pointer-to-member closure: trivial intent, arcane implementation Jakob Bohm <jb-usenet@wisemo.com> - 2015-03-26 12:09 -0600
Re: object and pointer-to-member closure: trivial intent, arcane implementation via.usov@googlemail.com - 2015-03-30 12:21 -0600
csiph-web