Topic: Bound member functions


Author: int19h@gmail.com
Date: Tue, 18 Dec 2007 08:35:41 CST
Raw View
Alberto Ganesh Barbati wrote:

> I've posted on the subject of bound member functions before, proposing a
> library solution to address the issue, but a recent post by Matthew
> Elkins made me think about the expressions:
>
>    obj.*func
>    ptr->*func
>
> where func is a member function. All we currently know is that:
>
> 1) The result is a function of the type specified by the second operand
> (see 5.5/2 and 5.5/3).
>
> 2) The result can be used only as the operand for the function call
> operator () (see 5.5/6)
>
> I find the choice of the word "function" in 5.5/2 and 5.5/3 very fishy,
> but let's ignore that.
>
> Now, 5.5/6, makes this code
>
>   auto bound_func = obj.*func;
>   bound_func();
>
> illegal, however I believe a lot of people would agree with me that it
> would be a wonderful thing to have in the language.

Like I've said before, it also makes perfect sense when combined with
the lambda proposal, since lambdas already require the compiler to
provide an efficient representation that can be reused here. And
furthermore, if this syntax is just a syntactic sugar for a lambda,
then all the semantics are already described in the lambda proposal.

> One possible reason that may have made obj.*func difficult to treat as a
> callable object (rather than a "function") is that it's impossible to
> describe its type with the C++ declarator syntax. However, that's no
> longer an issue! The types of those expressions can be very simply
> described in C+0x with:
>
>   decltype(obj.*func)
>   decltype(ptr->*func)
>
> Of course, by using auto, we don't even need to use declspec.

In fact, with variadic template arguments, we can describe the type
explicitly as well. It could even be std::function, but there is a
better option. If we make .* and ->* syntactic sugar for <&>, the type
would be std::nested_function, which is potentially (and very likely
to be) a much more efficient representation.

Why specify the type, and not leave it undefined? Mostly so that bound
functions can be stored and passed around as arguments. std::function
is just too generic and heavyweight, all too often there's really
little need in all that it provides - plain function pointers and
bound members suffice just fine.

---
[ 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.comeaucomputing.com/csc/faq.html                      ]





Author: AlbertoBarbati@libero.it (Alberto Ganesh Barbati)
Date: Thu, 6 Dec 2007 20:31:56 GMT
Raw View
Andrei Polushin ha scritto:
> Alberto Ganesh Barbati wrote:
>> Now, 5.5/6, makes this code
>>
>>   auto bound_func = obj.*func;
>>   bound_func();
>>
>> illegal, however I believe a lot of people would agree with me that it
>> would be a wonderful thing to have in the language.
>
> You refer to 5.5/6 specifically, while even 5.2.5/4 has the similar
> wording, and describes the binding more naturally. In particular, it
> could be possible to allow this:
>
>     class A {
>     public:
>         void f();   // member function declared
>     };
>
>     A x;
>     auto xf = x.f;  // "bound member function" object
>     xf();           // callable

I apologize. I realized that in my post I wrote "where func is a member
function", while actually I meant "where func is a pointer to member
function". That's why I was referring to .* and ->* and cited section
5.5. Operator "." is completely different beast and I have no intention
to mess with it. See below for one (among several) reason.

> BTW, this syntax is perfectly legal in Python, see "Method Objects" at
> http://docs.python.org/tut/node11.html#SECTION0011340000000000000000

Yes, I know that perfectly. Actually it was my primary source of
inspiration. Thanks for point that out, though.

>
> Did you mean something like this:
>
>     class A {
>     public:
>         void f();
>         void f(int a);
>         void f(int a, int b);
>     };
>
> <snip>
>
>     A x;
>     auto xf = x.f;  // "auto" is the compiler-generated type A_f above
>     xf();           // effectively calls A::f()
>     xf(1);          // effectively calls A::f(int)
>     xf(1, 2);       // effectively calls A::f(int, int)
>

Absolutely no. As you see, messing with operator "." requires you to
cope with function overloading. I don't want that. Moreover that would
be in open conflict with my desire to perform virtual resolution at the
binding site rather than at the call site. Working with pointers to
member functions has no such problem, because overloading has already
happened (it happened the moment the pointer is obtained with operator "&").

According to my proposal, your example would read differently:

  A x;
  void (A::*pf)() = &A::f; // overloading resolution happens here!
  auto xf = x.*pf;         // binding happens here
  xf();                    // effectively calls A::f()
  xf(1);                   // illegal!
  xf(1, 2);                // illegal!

>
> It would be great if someone would invent a good syntax to bind an
> arbitrary number of function parameters, something like:
>
>     auto xf2 = x.f(_, 2);   // binds "this" pointer,
>                             // and the second parameter, but
>                             // leaves the first parameter unbound.
>
>     xf2(1)                  // effectively calls x.f(1, 2)
>

We already have that. It's what std::bind is good for:

  using std::placeholders;
  auto xf2 = std::bind((void (A::*)())&A::f, &x, _1, 2); // notice: _1
  xf2(1); // effectively calls x.f(1, 2)

notice that in this particular case, where the function is overloaded
you have to use a cast to select the correct resolution at the binding
site. If no overloading is involved, the cast is not necessary.
std::bind actually does a lot more than that, if you don't know it, I
suggest you have a look at http://www.boost.org/libs/bind/bind.html.
Unfortunately, as I have shown in another post in this thread, despite
its obvious usefulness and great flexibility, std::bind can't help
solving the problem I would like addressed.

Regards,

Ganesh

---
[ 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.comeaucomputing.com/csc/faq.html                      ]





Author: Nicola Musatti <nicola.musatti@gmail.com>
Date: Mon, 10 Dec 2007 11:28:47 CST
Raw View
On Dec 3, 7:47 am, Alberto Ganesh Barbati <AlbertoBarb...@libero.it>
wrote:
> Hi Everybody,
>
> I've posted on the subject of bound member functions before, proposing a
> library solution to address the issue, but a recent post by Matthew
> Elkins made me think about the expressions:
>
>    obj.*func
>    ptr->*func
>
> where func is a member function. All we currently know is that:
>
> 1) The result is a function of the type specified by the second operand
> (see 5.5/2 and 5.5/3).
>
> 2) The result can be used only as the operand for the function call
> operator () (see 5.5/6)
>
> I find the choice of the word "function" in 5.5/2 and 5.5/3 very fishy,
> but let's ignore that.
>
> Now, 5.5/6, makes this code
>
>   auto bound_func = obj.*func;
>   bound_func();
>
> illegal, however I believe a lot of people would agree with me that it
> would be a wonderful thing to have in the language.

Bound member functions were proposed before to the standard committee:
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2002/n1384.pdf

The C++ binding to Borland/Codegear's VCL library uses them
extensively, although with a different syntax. Even though the library
itself is written in Delphi I would consider this a rather strong
argument in favour of bound members, in terms of both motivation and
previous experience.

Cheers,
Nicola Musatti

---
[ 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.comeaucomputing.com/csc/faq.html                      ]





Author: Alberto Ganesh Barbati <AlbertoBarbati@libero.it>
Date: Mon, 3 Dec 2007 00:47:43 CST
Raw View
Hi Everybody,

I've posted on the subject of bound member functions before, proposing a
library solution to address the issue, but a recent post by Matthew
Elkins made me think about the expressions:

   obj.*func
   ptr->*func

where func is a member function. All we currently know is that:

1) The result is a function of the type specified by the second operand
(see 5.5/2 and 5.5/3).

2) The result can be used only as the operand for the function call
operator () (see 5.5/6)

I find the choice of the word "function" in 5.5/2 and 5.5/3 very fishy,
but let's ignore that.

Now, 5.5/6, makes this code

  auto bound_func = obj.*func;
  bound_func();

illegal, however I believe a lot of people would agree with me that it
would be a wonderful thing to have in the language.

I do believe that there were very good reasons for having the
restriction in 5.5/6 back in C++99, although I ignore them. My question
is: are those reasons still good in 2007? We now know much more about
compiler technology, so maybe those reasons are no longer an impediment.
I mean, a bound member function can be implemented with just two
pointers! In fact, the implementation might even be simpler than a
pointer-to-member-function, because the resolution of virtual functions
and inheritance can be performed at the bounding site rather than at the
call site. Moreover, if expression on the right hand side is of the form
&C::func, the compiler might even be able to resolve the binding at
compile time without creating the pointer-to-member.

One possible reason that may have made obj.*func difficult to treat as a
callable object (rather than a "function") is that it's impossible to
describe its type with the C++ declarator syntax. However, that's no
longer an issue! The types of those expressions can be very simply
described in C+0x with:

  decltype(obj.*func)
  decltype(ptr->*func)

Of course, by using auto, we don't even need to use declspec.

Summarizing, I am suggesting that obj.*func and ptr->*func should be
objects (not functions) whose type T is unspecified, with:

1) T is a literal type: this would allow obj.*func to be a constant
expression whenever obj and func are constant expressions

2) T has no default constructor: the only way to get an object of type T
is by an expression involving .* or ->* or by copying an existing object

3) if t is an instance of T initialized with the expression obj.*func
(resp. ptr->*func), then the expression

   t(t1, t2, ..., tN)

invokes the member function func on object obj (resp. *ptr), with
parameters t1, t2, ... tN.

In order to avoid object lifetime issues while still allowing the
resolution of the bound function at the binding site, it might be enough
to say that if the dynamic type of the object at moment of invoking the
function differs from the dynamic type of the object at moment of
binding, then the behaviour is undefined.

Is there something terribly obvious that I'm missing? I know that it's
getting very late for new proposals, but if I were to write a formal
one, do you think it might stand a chance of being considered?

Thanks in advance,

Ganesh

---
[ 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.comeaucomputing.com/csc/faq.html                      ]





Author: Michael Aaron Safyan <michaelsafyan@aim.com>
Date: Mon, 3 Dec 2007 01:38:31 CST
Raw View
Alberto Ganesh Barbati wrote:
> Hi Everybody,
>
> I've posted on the subject of bound member functions before, proposing a
> library solution to address the issue, but a recent post by Matthew
> Elkins made me think about the expressions:
>
>    obj.*func
>    ptr->*func
>
> where func is a member function. All we currently know is that:
>
> 1) The result is a function of the type specified by the second operand
> (see 5.5/2 and 5.5/3).
>
> 2) The result can be used only as the operand for the function call
> operator () (see 5.5/6)
>
> I find the choice of the word "function" in 5.5/2 and 5.5/3 very fishy,
> but let's ignore that.
>
> Now, 5.5/6, makes this code
>
>   auto bound_func = obj.*func;
>   bound_func();
>
> illegal, however I believe a lot of people would agree with me that it
> would be a wonderful thing to have in the language.
>
> I do believe that there were very good reasons for having the
> restriction in 5.5/6 back in C++99, although I ignore them. My question
> is: are those reasons still good in 2007? We now know much more about
> compiler technology, so maybe those reasons are no longer an impediment.
> I mean, a bound member function can be implemented with just two
> pointers! In fact, the implementation might even be simpler than a
> pointer-to-member-function, because the resolution of virtual functions
> and inheritance can be performed at the bounding site rather than at the
> call site. Moreover, if expression on the right hand side is of the form
> &C::func, the compiler might even be able to resolve the binding at
> compile time without creating the pointer-to-member.
>
> One possible reason that may have made obj.*func difficult to treat as a
> callable object (rather than a "function") is that it's impossible to
> describe its type with the C++ declarator syntax. However, that's no
> longer an issue! The types of those expressions can be very simply
> described in C+0x with:
>
>   decltype(obj.*func)
>   decltype(ptr->*func)
>
> Of course, by using auto, we don't even need to use declspec.
>
> Summarizing, I am suggesting that obj.*func and ptr->*func should be
> objects (not functions) ...

What about passing the result of "obj.*func" or "ptr->*func" as an
argument to a function?

> [SNIPPED]
> Thanks in advance,
>
> Ganesh
>
> ---
> [ 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.comeaucomputing.com/csc/faq.html                      ]
>

---
[ 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.comeaucomputing.com/csc/faq.html                      ]





Author: Greg Herlihy <greghe@mac.com>
Date: Mon, 3 Dec 2007 10:05:32 CST
Raw View
On Dec 2, 10:47 pm, Alberto Ganesh Barbati <AlbertoBarb...@libero.it>
wrote:
>
> I've posted on the subject of bound member functions before, proposing a
> library solution to address the issue, but a recent post by Matthew
> Elkins made me think about the expressions:
>
>    obj.*func
>    ptr->*func
>
> where func is a member function. All we currently know is that:
>
> 1) The result is a function of the type specified by the second operand
> (see 5.5/2 and 5.5/3).
>
> 2) The result can be used only as the operand for the function call
> operator () (see 5.5/6)
>
> I find the choice of the word "function" in 5.5/2 and 5.5/3 very fishy,
> but let's ignore that.
>
> Now, 5.5/6, makes this code
>
>   auto bound_func = obj.*func;
>   bound_func();
>
> illegal, however I believe a lot of people would agree with me that it
> would be a wonderful thing to have in the language.

Why should bound member functions be implemented as a language
feature? Especially since the Standard Library will offer an equally
concise - but far more flexible - way to create bound member function
objects::

     auto bound_func = std::bind( &T::func, obj);
     bound_func();

After all, it's not clear from your example whether arguments to the
bound member function are also bound along with the class object - or
whether they are to be passed to the function when the bound member
function is called. With std::bind(), of course, either scenario is
supported - it's even possible to bind certain arguments and not
others - all within the same function object..

So I don't see that there is much of a case to be made for adding to
the language, a (less capable) version of a feature that has already
been added to the Standard Library.

Greg

---
[ 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.comeaucomputing.com/csc/faq.html                      ]





Author: Sean Hunt <rideau3@gmail.com>
Date: Mon, 3 Dec 2007 10:47:35 CST
Raw View
On Dec 3, 9:05 am, Greg Herlihy <gre...@mac.com> wrote:
> Why should bound member functions be implemented as a language
> feature? Especially since the Standard Library will offer an equally
> concise - but far more flexible - way to create bound member function
> objects::
>
>      auto bound_func = std::bind( &T::func, obj);
>      bound_func();

Overloading of the ->* operator is a good reason. In a smart pointer
class (assuming T is the type pointed to, ptr is pointer being
wrapped.):

template <typename U>
inline auto operator ->* (U T::* p) // Sorry if I got the syntax
wrong. You get the idea, right?
     -> ptr->*p
{
     if (!ptr)
          throw myCustomException;
     return ptr->*p;
}

Without a bound member function as a type, this won't work. Any other
solution simply won't cover the full range of possibilities that can
be done with this, such as ensuring all operators work for any type.

---
[ 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.comeaucomputing.com/csc/faq.html                      ]





Author: Sean Hunt <rideau3@gmail.com>
Date: Mon, 3 Dec 2007 13:07:24 CST
Raw View
I'd like to correct myself twice here. First, it should probably
return a reference, which I overlooked, but more importantly, operator
->* can be implemented using type traits, but it's difficult:

template <typename U, bool b = std::is_function<U>>
U& operator ->* (U T::* p)
{
     return ptr->*p;
}

template <typename U>
auto operator ->*<U, true> (U T::* p)
     -> std::bind(std::mem_fn(p), ptr)
{
     return std::bind(std::mem_fn(p), ptr)
}

I believe that this implementation has the correct results (assuming I
picked the right type trait and it works as I intend it to - the
<true> specialization gets used whenever it's a pointer to member
function).

Still, I'd like to not have to use type traits and auto-returning
functions to implement such a pointer.

This might also want to be pushed into the library, now that this
pointer is possible.

---
[ 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.comeaucomputing.com/csc/faq.html                      ]





Author: AlbertoBarbati@libero.it (Alberto Ganesh Barbati)
Date: Mon, 3 Dec 2007 21:22:22 GMT
Raw View
Michael Aaron Safyan ha scritto:
> Alberto Ganesh Barbati wrote:
>>
>> 2) The result can be used only as the operand for the function call
>> operator () (see 5.5/6)
>>
>> <snip>
>>
>> Summarizing, I am suggesting that obj.*func and ptr->*func should be
>> objects (not functions) ...
>
> What about passing the result of "obj.*func" or "ptr->*func" as an
> argument to a function?
>

The problem is that 5.5/6 makes that illegal. However, my suggestion
would make that legal.

Ganesh

---
[ 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.comeaucomputing.com/csc/faq.html                      ]





Author: AlbertoBarbati@libero.it (Alberto Ganesh Barbati)
Date: Mon, 3 Dec 2007 21:23:37 GMT
Raw View
Sean Hunt ha scritto:
> Overloading of the ->* operator is a good reason. In a smart pointer
> class (assuming T is the type pointed to, ptr is pointer being
> wrapped.):
>
> template <typename U>
> inline auto operator ->* (U T::* p) // Sorry if I got the syntax
> wrong. You get the idea, right?
>      -> ptr->*p

I guess you mean
       -> decltype(ptr->*p)
> {
>      if (!ptr)
>           throw myCustomException;
>      return ptr->*p;
> }
>
> Without a bound member function as a type, this won't work. Any other
> solution simply won't cover the full range of possibilities that can
> be done with this, such as ensuring all operators work for any type.

Yes, that's precisely one use case and a very good one.

> I'd like to correct myself twice here. First, it should probably
> return a reference, which I overlooked, [...]

No. According to my proposal, decltype(ptr->*p) is a type than can be
safely copied and should actually returned by value.

> return a reference, which I overlooked, but more importantly, operator
> ->* can be implemented using type traits, but it's difficult:
>
> template <typename U, bool b = std::is_function<U>>
> U& operator ->* (U T::* p)
> {
>      return ptr->*p;
> }
>
> template <typename U>
> auto operator ->*<U, true> (U T::* p)
>      -> std::bind(std::mem_fn(p), ptr)

Again, you missed the decltype here.

> {
>      return std::bind(std::mem_fn(p), ptr)
> }

the call to mem_fn is actually unnecessary. you can simply write
std::bind(p, ptr).

Anyway, your example is good for member functions that has exactly no
parameters. What if they have some? Let's rewrite the example, the
difference is minimal:

  template <typename U, typename... Args>
  inline auto operator ->* (U (T::*p)(Args...))
    -> decltype(ptr->*p)
  {
    return ptr->*p;
  }

(notice that you no longer need to rely on std::is_function nor on
std::bind)

I challenge you to rewrite the same code with std::bind. You need to
convert the template argument pack Args to a sequence of placeholders
_1, _2, etc. There may be MPL techniques able to do that, but I bet that
it's going to be painful.

HTH,

Ganesh

---
[ 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.comeaucomputing.com/csc/faq.html                      ]





Author: AlbertoBarbati@libero.it (Alberto Ganesh Barbati)
Date: Mon, 3 Dec 2007 21:22:55 GMT
Raw View
Greg Herlihy ha scritto:
> On Dec 2, 10:47 pm, Alberto Ganesh Barbati <AlbertoBarb...@libero.it>
> wrote:
>>
>> Now, 5.5/6, makes this code
>>
>>   auto bound_func = obj.*func;
>>   bound_func();
>>
>> illegal, however I believe a lot of people would agree with me that it
>> would be a wonderful thing to have in the language.
>
> Why should bound member functions be implemented as a language
> feature? Especially since the Standard Library will offer an equally
> concise - but far more flexible - way to create bound member function
> objects::
>
>      auto bound_func = std::bind( &T::func, obj);
>      bound_func();

Unfortunately that is not what I want. It's all ok if T::func has no
parameters, but if T::func has N parameters, then the first line becomes:

  auto bound_func = std::bind(&T::func, obj, _1, _2, ... _N);

and this notation has the following problems:

1) you have to know in advance the exact number of parameters
2) if you have several parameters the notation can be verbose
3) depending on the quality of the implementation, the representation of
 bound_func may require an allocation on the heap and the storage is
probably larger than the two pointers that are actually required
4) it is very unlikely that the result of std::bind qualifies as a
literal type
5) the resolution of virtual functions is performed at the call site
rather than a bind site

As I reminded in the OP, I already shown in a different thread
(http://tinyurl.com/29etuy) these problems of std::bind and proposed a
library approach by overloading std::mem_fn. You should remember that,
as you contributed to the discussion.

> After all, it's not clear from your example whether arguments to the
> bound member function are also bound along with the class object - or
> whether they are to be passed to the function when the bound member
> function is called. With std::bind(), of course, either scenario is
> supported - it's even possible to bind certain arguments and not
> others - all within the same function object..

Nono. Only the object is bound, not the arguments. Frankly, I believe
that was very clear from my post so I don't understand where did you get
this doubt. .* and ->* are binary operators, so no expressions other
than the object and function pointer are involved.

std::bind may be able to implement both scenario but, as I've shown,
it's not very good at binding only the object, IMHO.

> So I don't see that there is much of a case to be made for adding to
> the language, a (less capable) version of a feature that has already
> been added to the Standard Library.

Because I don't think it is less capable and because I don't think that
"less capable" is a bad thing. It does something different (although
very similar) from std::bind and, being somewhat simpler, can be
definitely more efficient than that. Moreover, in order to perform
virtual resolution at the binding site you need a deeper knowledge about
how the virtual dispatch is achieve and that looks more like the job for
a language feature than for a library component.

Just my opinion,

Ganesh

---
[ 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.comeaucomputing.com/csc/faq.html                      ]





Author: "Roman.Perepelitsa@gmail.com" <Roman.Perepelitsa@gmail.com>
Date: Tue, 4 Dec 2007 08:37:57 CST
Raw View
On 3 Dec, 09:47, Alberto Ganesh Barbati <AlbertoBarb...@libero.it>
wrote:
> In fact, the implementation might even be simpler than a
> pointer-to-member-function, because the resolution of virtual functions
> and inheritance can be performed at the bounding site rather than at the
> call site.

In my opinion, ability to perform virtual function resolution and
invoke
function later is very important.

1. Virtual function call consists of 2 actions: finding actual
function's
address and performing regular function call. Unfortunately, we
can't reuse result of the 1st action. It's not uncommon to call
virtual function of the same object many times, therefore
eliminating virtual call by caching devirtualized function would
sometimes improve performance.
2. Once I had to hack application that performed single virtual
call on each attempt to write something to log. Using the
knowledge of virtual table layout (which is compiler and platform
dependent of course) I performed manual devirtualization.
It improved performance significantly.

Regards,
Roman Perepelitsa.

---
[ 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.comeaucomputing.com/csc/faq.html                      ]





Author: Sean Hunt <rideau3@gmail.com>
Date: Tue, 4 Dec 2007 14:44:26 CST
Raw View
On Dec 3, 2:23 pm, AlbertoBarb...@libero.it (Alberto Ganesh Barbati)
wrote:
> Sean Hunt ha scritto:
>
> > Overloading of the ->* operator is a good reason. In a smart pointer
> > class (assuming T is the type pointed to, ptr is pointer being
> > wrapped.):
>
> > template <typename U>
> > inline auto operator ->* (U T::* p) // Sorry if I got the syntax
> > wrong. You get the idea, right?
> >      -> ptr->*p
>
> I guess you mean
>        -> decltype(ptr->*p)

I guess. I was under the impression that the -> mean an implicit
decltype (because "-> int" would be stupid. You could just have
declared that as the normal type).

>
> > {
> >      if (!ptr)
> >           throw myCustomException;
> >      return ptr->*p;
> > }
>
> > Without a bound member function as a type, this won't work. Any other
> > solution simply won't cover the full range of possibilities that can
> > be done with this, such as ensuring all operators work for any type.
>
> Yes, that's precisely one use case and a very good one.
>
> > I'd like to correct myself twice here. First, it should probably
> > return a reference, which I overlooked, [...]
>
> No. According to my proposal, decltype(ptr->*p) is a type than can be
> safely copied and should actually returned by value.

But in order to return an lvalue, it must return a reference.
Otherwise:

foo->*p = 3;

would be incorrect.

> > return a reference, which I overlooked, but more importantly, operator
> > ->* can be implemented using type traits, but it's difficult:
>
> > template <typename U, bool b = std::is_function<U>>
> > U& operator ->* (U T::* p)
> > {
> >      return ptr->*p;
> > }
>
> > template <typename U>
> > auto operator ->*<U, true> (U T::* p)
> >      -> std::bind(std::mem_fn(p), ptr)
>
> Again, you missed the decltype here.

Fair enough.

> > {
> >      return std::bind(std::mem_fn(p), ptr)
> > }
>
> the call to mem_fn is actually unnecessary. you can simply write
> std::bind(p, ptr).

std::bind binds argument types. Not the implicit object parameter,
unless I have dearly misunderstood the function.

> Anyway, your example is good for member functions that has exactly no
> parameters. What if they have some? Let's rewrite the example, the
> difference is minimal:

U can be typed to a specific function or to any non-function type the
way I wrote it. It doesn't matter if it's int(U)(int, float) or myType
U. It always works.
>
>   template <typename U, typename... Args>
>   inline auto operator ->* (U (T::*p)(Args...))
>     -> decltype(ptr->*p)
>   {
>     return ptr->*p;
>   }
>
> (notice that you no longer need to rely on std::is_function nor on
> std::bind)

Hmm... I don't think that you can specialize for any sort of function
type:

template <typename U, typename V = char, typename Args...> class foo
{ ... };

template <typename V, typename Args...> class foo <V U (Args...)>
{ ... };

I'm pretty sure that doesn't work, so the type_traits is the only way
to determine the presence of a functional type.

> I challenge you to rewrite the same code with std::bind. You need to
> convert the template argument pack Args to a sequence of placeholders
> _1, _2, etc. There may be MPL techniques able to do that, but I bet that
> it's going to be painful.

You misunderstand operator->*. It simply returns an object. In the
expression (foo->*p)(i), the result of operator ->* is called with the
parameter i. As a result, I must return an object that is suitable for
a call with i (but not necessarily anything else) when I get a pointer
to function, but when I get a pointer to object, I must return it as
an lvalue.


Sean

---
[ 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.comeaucomputing.com/csc/faq.html                      ]





Author: AlbertoBarbati@libero.it (Alberto Ganesh Barbati)
Date: Tue, 4 Dec 2007 22:18:16 GMT
Raw View
Sean Hunt ha scritto:
> On Dec 3, 2:23 pm, AlbertoBarb...@libero.it (Alberto Ganesh Barbati)
> wrote:
>> Sean Hunt ha scritto:
>>
>>> I'd like to correct myself twice here. First, it should probably
>>> return a reference, which I overlooked, [...]
>> No. According to my proposal, decltype(ptr->*p) is a type than can be
>> safely copied and should actually returned by value.
>
> But in order to return an lvalue, it must return a reference.
> Otherwise:
>
> foo->*p = 3;
>
> would be incorrect.

There must be a misunderstanding. My idea was only about binding member
*functions* (as the subject of this post should have suggested). I was
not considering data members.

>
>>> {
>>>      return std::bind(std::mem_fn(p), ptr)
>>> }
>> the call to mem_fn is actually unnecessary. you can simply write
>> std::bind(p, ptr).
>
> std::bind binds argument types. Not the implicit object parameter,
> unless I have dearly misunderstood the function.

I don't understand what you mean by that, but I can assure that

  bind(mem_fn(p), ptr)

and

  bind(p, ptr)

are equivalent whenever p is a pointer to member function.

>> Anyway, your example is good for member functions that has exactly no
>> parameters. What if they have some? Let's rewrite the example, the
>> difference is minimal:
>
> U can be typed to a specific function or to any non-function type the
> way I wrote it. It doesn't matter if it's int(U)(int, float) or myType
> U. It always works.

It may compile, but it doesn't "work" in the general case. The problem
is that std::bind(p, ptr) returns an object B such that

  B(a1, a2, ... aN)

eventually resolves to:

  (ptr->*p)();

regardless of N, so the member function identified by p must be callable
without parameters.

>>   template <typename U, typename... Args>
>>   inline auto operator ->* (U (T::*p)(Args...))
>>     -> decltype(ptr->*p)
>>   {
>>     return ptr->*p;
>>   }
>>
>> (notice that you no longer need to rely on std::is_function nor on
>> std::bind)
>
> Hmm... I don't think that you can specialize for any sort of function
> type:
>
> template <typename U, typename V = char, typename Args...> class foo
> { ... };
>
> template <typename V, typename Args...> class foo <V U (Args...)>
> { ... };
>
> I'm pretty sure that doesn't work, so the type_traits is the only way
> to determine the presence of a functional type.

What you wrote (with functions) doesn't work, but what I wrote (with
pointer to member functions) should. At least it does without template
argument packs and I don't see why it shouldn't with them.

>> I challenge you to rewrite the same code with std::bind. You need to
>> convert the template argument pack Args to a sequence of placeholders
>> _1, _2, etc. There may be MPL techniques able to do that, but I bet that
>> it's going to be painful.
>
> You misunderstand operator->*. It simply returns an object. In the
> expression (foo->*p)(i), the result of operator ->* is called with the
> parameter i. As a result, I must return an object that is suitable for
> a call with i (but not necessarily anything else) when I get a pointer
> to function, but when I get a pointer to object, I must return it as
> an lvalue.

I repeat, my post was only about pointer to member functions, not
pointer to data members.

Anyway what you say is incorrect. *For member functions* the standard
currently says that ->* does *not* return an object, but returns a
function (see 5.5/3). Indeed *I* am proposing to change that and make
->* return a callable object instead.

Ganesh

PS: A function is *not* an object (see 1.8/1).

---
[ 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.comeaucomputing.com/csc/faq.html                      ]





Author: pete@versatilecoding.com (Pete Becker)
Date: Wed, 5 Dec 2007 03:50:30 GMT
Raw View
On 2007-12-04 09:44:26 -0500, Sean Hunt <rideau3@gmail.com> said:

> On Dec 3, 2:23 pm, AlbertoBarb...@libero.it (Alberto Ganesh Barbati)
> wrote:
>>> {
>>> return std::bind(std::mem_fn(p), ptr)
>>> }
>>
>> the call to mem_fn is actually unnecessary. you can simply write
>> std::bind(p, ptr).
>
> std::bind binds argument types. Not the implicit object parameter,
> unless I have dearly misunderstood the function.

std::bind handles pointers to member functions and pointers to member
data correctly: the next argument is recognized as the object (or
pointer to object, or smart pointer to object) to apply the pointer to.

--
  Pete
Roundhouse Consulting, Ltd. (www.versatilecoding.com) Author of "The
Standard C++ Library Extensions: a Tutorial and Reference
(www.petebecker.com/tr1book)


---
[ 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.comeaucomputing.com/csc/faq.html                      ]





Author: Andrei Polushin <polushin@gmail.com>
Date: Wed, 5 Dec 2007 17:16:48 CST
Raw View
Alberto Ganesh Barbati wrote:
> Now, 5.5/6, makes this code
>
>   auto bound_func = obj.*func;
>   bound_func();
>
> illegal, however I believe a lot of people would agree with me that it
> would be a wonderful thing to have in the language.

You refer to 5.5/6 specifically, while even 5.2.5/4 has the similar
wording, and describes the binding more naturally. In particular, it
could be possible to allow this:

    class A {
    public:
        void f();   // member function declared
    };

    A x;
    auto xf = x.f;  // "bound member function" object
    xf();           // callable


BTW, this syntax is perfectly legal in Python, see "Method Objects" at
http://docs.python.org/tut/node11.html#SECTION0011340000000000000000


> Summarizing, I am suggesting that obj.*func and ptr->*func should be
> objects (not functions) whose type T is unspecified, with:
>
> 1) T is a literal type: this would allow obj.*func to be a constant
> expression whenever obj and func are constant expressions
>
> 2) T has no default constructor: the only way to get an object of type T
> is by an expression involving .* or ->* or by copying an existing object
>
> 3) if t is an instance of T initialized with the expression obj.*func
> (resp. ptr->*func), then the expression
>
>    t(t1, t2, ..., tN)
>
> invokes the member function func on object obj (resp. *ptr), with
> parameters t1, t2, ... tN.

Did you mean something like this:

    class A {
    public:
        void f();
        void f(int a);
        void f(int a, int b);
    };

/*
    class A_f {     // compiler-generated bindings of A::f
        A& that;
    public:
        A_f(A& that) : that(that) {}

        void operator()() const
        {
            that.f();
        }
        void operator()(int a) const
        {
            that.f(a);
        }
        void operator()(int a, int b) const
        {
            that.f(a, b);
        }
    };
*/

    A x;
    auto xf = x.f;  // "auto" is the compiler-generated type A_f above
    xf();           // effectively calls A::f()
    xf(1);          // effectively calls A::f(int)
    xf(1, 2);       // effectively calls A::f(int, int)


> Is there something terribly obvious that I'm missing?

It would be great if someone would invent a good syntax to bind an
arbitrary number of function parameters, something like:

    auto xf2 = x.f(_, 2);   // binds "this" pointer,
                            // and the second parameter, but
                            // leaves the first parameter unbound.

    xf2(1)                  // effectively calls x.f(1, 2)


--
Andrei Polushin

---
[ 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.comeaucomputing.com/csc/faq.html                      ]