A proposal to introduce an optional parameter for mem_fn to bind to an object to its member function

356 views
Skip to first unread message

Mikhail Semenov

unread,
May 29, 2013, 4:24:26 PM5/29/13
to std-pr...@isocpp.org
This proposal is to add a second, optional parameter to mem_fn, which allows to bind an object to its member function:
 
class A2
{
    int i;
public:   
    A2(int k):i(k) {}
   
    auto f8 (int a1, int a2, int a3, int a4, int a5, int a6, int a7, int a8) const -> int
    {
        return i+a1+a2+a3+a4+a5+a6+a7+a8;
    }       
};
 
A2 a(10.0);
 
auto af8 = std::mem_fn(&A2::f8, &a); // shorter then writing a bind
 
Now we can use it as follows:
 
int z = af8(1,2,3,4,5,6,7,8);
 
mem_fn_optional_parameter_proposal.pdf

DeadMG

unread,
May 29, 2013, 5:24:21 PM5/29/13
to std-pr...@isocpp.org
Except you could just do `std::bind(std::mem_fn(&A2::f8), &a)`, which is hardly more arduous.

Zhihao Yuan

unread,
May 29, 2013, 5:29:26 PM5/29/13
to std-pr...@isocpp.org
On Wed, May 29, 2013 at 4:24 PM, Mikhail Semenov
<mikhailse...@gmail.com> wrote:
> auto af8 = std::mem_fn(&A2::f8, &a); // shorter then writing a bind

First, this makes the 2 variations of `std::mem_fn`
have different lifetimes.

Second... why bother pointers to objects?

--
Zhihao Yuan, ID lichray
The best way to predict the future is to invent it.
___________________________________________________
4BSD -- http://4bsd.biz/

Jonathan Wakely

unread,
May 30, 2013, 7:34:18 AM5/30/13
to std-pr...@isocpp.org


On Wednesday, May 29, 2013 10:24:21 PM UTC+1, DeadMG wrote:
Except you could just do `std::bind(std::mem_fn(&A2::f8), &a)`, which is hardly more arduous.

No you can't.

Well, you can, but you can't call it, because the call wrapper returned by that bind() would not forward any arguments to the target function, so would not be usable.  You'd need to bind placeholders::_1 through placeholders::_8.

Jonathan Wakely

unread,
May 30, 2013, 8:22:31 AM5/30/13
to std-pr...@isocpp.org

Also that would be std::bind(&A2::f8, &a, placeholders::_1, ...) because bind implements the INVOKE protocol so already handles pointers to members without needing mem_fn.

What would actually be useful and solve the OP's problem in a more consistent way would be std::bind(&A2::f8, &a, std::placeholders::all) or something that allows ranges or groups of unbound arguments.  This would be more consistent than overloading std::mem_fn, because the lifetime of bind expressions already depends on the lifetime of the arguments, so would address lichray's concern.

 

Xeo

unread,
May 30, 2013, 9:28:05 AM5/30/13
to std-pr...@isocpp.org
Writing such an "easy_bind" / "mem_bind" is actually rather simple, since we can tell `std::bind` about our own placeholder types (using C++14 return-type deduction for brevity):

#include <functional>
#include <utility>
#include <type_traits>

template<unsigned... Is> struct seq{};
template<unsigned I, unsigned... Is>
struct gen_seq : gen_seq<I-1, I-1, Is...>{};
template<unsigned... Is>
struct gen_seq<0, Is...> : seq<Is...>{};

template<unsigned I> struct placeholder{};

namespace std{
template<unsigned I>
struct is_placeholder<::placeholder<I>> : integral_constant<int, I>{};
} // std::

namespace aux{
template<unsigned... Is, class F, class... Ts>
auto easy_bind(seq<Is...>, F&& f, Ts&&... vs){
   
return std::bind(std::forward<F>(f), std::forward<Ts>(vs)..., ::placeholder<1 + Is>()...);
}
} // aux::

template<class R, class C, class... FArgs, class... Args>
auto mem_bind(R (C::*ptmf)(FArgs...), Args&&... vs){
   
// the +1s for 'this' argument
   
static_assert(sizeof...(Args) <= sizeof...(FArgs) + 1, "too many arguments to mem_bind");
   
return aux::easy_bind(gen_seq<(sizeof...(FArgs) + 1) - sizeof...(Args)>(), ptmf, std::forward<Args>(vs)...);
}

template<class T, class C, class... Args>
auto mem_bind(T C::*ptmd, Args&&... vs){
   
// just 'this' argument
   
static_assert(sizeof...(Args) <= 1, "too many arguments to mem_bind");
   
return aux::easy_bind(gen_seq<1 - sizeof...(Args)>(), ptmd, std::forward<Args>(vs)...);
}


With a live example.

Jonathan Wakely

unread,
May 30, 2013, 9:38:07 AM5/30/13
to std-pr...@isocpp.org
On Thursday, May 30, 2013 2:28:05 PM UTC+1, Xeo wrote:
Writing such an "easy_bind" / "mem_bind" is actually rather simple, since we can tell `std::bind` about our own placeholder types (using

Very nice, I hadn't thought of doing it with user-defined placeholders.
 
C++14 return-type deduction for brevity):

You could have also used std::integer_sequence for more brevity ;-)

Mikhail Semenov

unread,
Jun 1, 2013, 3:28:49 AM6/1/13
to std-pr...@isocpp.org
That is not simple.
This is simple:
template <class _OBJECT,class _T,class _R>
struct _delegate{};
template<class _OBJECT1, class _T, class _R, class ... _Arg>
class _delegate<_OBJECT1,_T,_R(_Arg...)>
{
    _OBJECT1 _obj;
    _R (_T::*f1)(_Arg ... );
public:
   
    _delegate (_R (_T::*_fx)(_Arg ... ), _OBJECT1 _obj1):_obj(_obj1),f1(_fx)
    {
    }
    _R operator()(_Arg ...  _x)
    {
        return ((*_obj).*f1)(std::forward<_Arg>(_x) ...);
    }
};
template<class _OBJECT, class _T, class _R, class ... _Arg>
_delegate<_OBJECT,_T,_R(_Arg ...)> mem_fn(_R (_T::*_f)(_Arg ... ), _OBJECT _obj)
{
    return _delegate<_OBJECT,_T,_R(_Arg ...)>(_f, _obj);
}
 
 

On Thursday, May 30, 2013 2:28:05 PM UTC+1, Xeo wrote:

Xeo

unread,
Jun 1, 2013, 7:22:42 AM6/1/13
to std-pr...@isocpp.org
Your version may seem easier, but I think it also leaves much to be desired:

* It can't deal with object references or member *data* pointers
* It gets perfect forwarding wrong. (easily fixed, though)
* It also can't be used for function composition through `std::bind` (can also be fixed, see `std::is_bind_expression`)
* It doesn't allow binding of extra arguments besides `this` optionally (if I can bind `this`, why not other things too? Why should I do `std::bind(std::mem_fn(f, this), ...)`?)

Mikhail Semenov

unread,
Jun 1, 2013, 10:29:08 AM6/1/13
to std-pr...@isocpp.org
Xeo,
 
(1) This version works with shared pointers.
(2) This is not perfect-forwarding: I could have easily used static_cast<Arg>(_x) as well (I probably should have). This is different. You "your  version" with various functions you'll see a problem.  Perfect-forwarding is used when you select the function depending on the parameters. You don't use it here. The function pointer is already available.
(3) I have defined it for pointers to members only. I am not interested in other bindings.
 
What I haven't covered is various qualifiers (const, volatile, const volatile). I just need extra definitions...
 
Here we have been discussing my proposal with two parameters. From this point of view, the only difference I see is in the use of the object:
the second parameter is your case is the object itself or a shared pointer, in my case its  a pointer to an object or a shared pointer (or whatever smart pointer
one wants to use). I have attached some files with examples and timing comparison between yours and mine.
 
By the way, in GCC (C++) in debug mode bind is pretty slow, but that's an implementation issue.
 
Mikhail.
mem_bind2.cpp
mem_bind3.cpp
mem_bind4.cpp

Jonathan Wakely

unread,
Jun 3, 2013, 4:48:56 AM6/3/13
to std-pr...@isocpp.org
On Saturday, June 1, 2013 3:29:08 PM UTC+1, Mikhail Semenov wrote:
 
By the way, in GCC (C++) in debug mode bind is pretty slow, but that's an implementation issue.

I won't comment on the rest (e.g. to point out perfect forwarding is still relevant in this case) but will just say that I don't know what you mean by "GCC in debug mode", but since libstdc++'s Debug Mode doesn't affect std::bind I assume you're just talking about unoptimized code, so talking about performance is a bit pointless.

Mikhail Semenov

unread,
Jun 3, 2013, 5:54:43 AM6/3/13
to std-pr...@isocpp.org
Jonathan,
 
I don't think it is completely pointless. Most of the time we run our code in debug mode.
 
Mikhail.

Jonathan Wakely

unread,
Jun 3, 2013, 6:24:46 AM6/3/13
to std-pr...@isocpp.org
On Monday, June 3, 2013 10:54:43 AM UTC+1, Mikhail Semenov wrote:
Jonathan,
 
I don't think it is completely pointless. Most of the time we run our code in debug mode.


I'm still not sure what you mean by "debug mode", GCC allows debugging symbols with -O3, and allows no debugging symbols with -O0, so if you really mean "unoptimized" then say so.

If that is what you mean then it's a case of "Doctor, Doctor, when I don't optimize my code it runs slowly." "Don't do that then."

GCC's std::bind should be close to optimal, AFAIK it does no copying or moving that isn't required by the standard. Maybe you should look at the -Og option, to get better performance without sacrificing debuggability.  The implementation already provides solutions, if you choose not to use them then that's not an implementation issue.

toma...@gmail.com

unread,
Jul 13, 2013, 8:52:27 AM7/13/13
to std-pr...@isocpp.org
I like the idea of your proposal N3702, but I think the mem_fn(pm, t) accept at optional parameter any object t, for which the INOVKE(pm, t, args...) will be well-formed: that means raw-pointers, smart-pointers and other pointer like types.

Mikhail Semenov

unread,
Jul 13, 2013, 3:03:14 PM7/13/13
to std-pr...@isocpp.org
Yes, this is exactly what  the proposal as about: as long as (*a).f makes sense the second  parameter is a "pointer" a: mem_fn(&A::f, a).  Some of the examples in N3702 show the use of shared pointers.

 
Message has been deleted

toma...@gmail.com

unread,
Jul 13, 2013, 7:34:11 PM7/13/13
to std-pr...@isocpp.org
The wording from the proposal miss the case of the smart pointers:
template<class R, class T> unspecified mem_fn(R T::*, cv T* obj);
The function with proposed signature will only accept raw pointers. Also would you like to allow binding a copy of object with the member pointer, it may be useful in same cases. Also I am working of proposal to extend INOVKE for member pointers to support compatible types, see forum discussion.

Mikhail Semenov

unread,
Jul 14, 2013, 4:56:08 AM7/14/13
to std-pr...@isocpp.org

Thank you for that remark.  The implementation (further one), though, allows a smart pointer. I think the wording should be changed.

Mikhail Semenov

unread,
Jul 14, 2013, 5:46:59 AM7/14/13
to std-pr...@isocpp.org

The change should be as follows:

 

template<class R, class T, class ObjT>

                            unspecified mem_fn(R T::*, ObjT obj);

 

instead of the following in N3702

    template<class R, class T> unspecified mem_fn(R T::*, cv T* obj);

 

As for INVOKE itself, as far as I understand, it is already supported. In 20.10.2:

 

Define
INVOKE (f, t1, t2, ..., tN) as follows:
- (t1.*f)(t2, ..., tN) when f is a pointer to a member function of a class T and t1 is an object of
  type T or a reference to an object of type T or a reference to an object of a type derived from T;
— ((*t1).*f)(t2, ..., tN) when f is a pointer to a member function of a class T and t1 is not one of
  the types described in the previous item;
— t1.*f when N == 1 and f is a pointer to member data of a class T and t1 is an object of type T or a
  reference to an object of type T or a reference to an object of a type derived from T;
— (*t1).*f when N == 1 and f is a pointer to member data of a class T and t1 is not one of the types described in the previous item;
— f(t1, t2, ..., tN) in all other cases.

 

The point is that std::bind already supports smart pointers correctly. It is already reflected in the well-known implementations.

toma...@gmail.com

unread,
Jul 19, 2013, 3:43:13 PM7/19/13
to std-pr...@isocpp.org


W dniu niedziela, 14 lipca 2013 11:46:59 UTC+2 użytkownik Mikhail Semenov napisał:

The change should be as follows:

 

template<class R, class T, class ObjT>

                            unspecified mem_fn(R T::*, ObjT obj);

 

instead of the following in N3702

    template<class R, class T> unspecified mem_fn(R T::*, cv T* obj);

 

Then you should add the requirement clause for the wording to the version of mem_fn with object:
Requires: ObjT shall be CopyConstructible.
And change the the clause:
Throws: Nothing.
To something similar to:
Throws: Nothing unless the selected constructor of ObjT trows.

Also you can drop the CV-qualification part of the statements pm is a pointer to member function with cv-qualifier cv and change it to pm is a pointer to member function, because it is not used in the definition of argument types.




Mikhail Semenov

unread,
Jul 20, 2013, 9:27:19 AM7/20/13
to std-pr...@isocpp.org
As the proposal stands at the moment if should be defined as follows:

template<class R, class T, class ObjT, class … Arg>

                            unspecified mem_fn(R (T::* pm)(Arg …) cv, ObjT obj);

 

Returns: A simple call wrapper (20.10.1) fn such that the expression fn(a1, ..., aN) is equivalent to ((*obj).*pm)(a1,…, aN). fn shall have a nested type result_type that is a synonym for the return type of pm when pm is a pointer to member function.

The simple call wrapper shall define one nested type named result_type as a synonym for Ret, where Ret  is pm’s return type.

The simple call wrapper shall define two nested types named argument_type and result_type as synonyms for T1 and Ret, respectively, when pm is a pointer to member function taking  one argument of type T1, where Ret is pm’s return type.

The simple call wrapper shall define three nested types named first_argument_type, second_argument_type, and result_type as synonyms for T1, T2, and Ret, respectively, when pm is a pointer to member function taking two arguments of types T1 and  T2, where Ret is pm’s return type.

Throws: Nothing unless the evaluation of obj throws.

______________________________________________________________________________________________________________________________

In comparison, the definition of bind allows to use as a second argument not only a pointer to an object or a smart-pointer but also an object itself. If we want to do something like that the proposed definition of mem_fn should be extended.

toma...@gmail.com

unread,
Jul 20, 2013, 12:26:24 PM7/20/13
to std-pr...@isocpp.org


W dniu sobota, 20 lipca 2013 15:27:19 UTC+2 użytkownik Mikhail Semenov napisał:
As the proposal stands at the moment if should be defined as follows:

template<class R, class T, class ObjT, class … Arg>

                            unspecified mem_fn(R (T::* pm)(Arg …) cv, ObjT obj);

 

Returns: A simple call wrapper (20.10.1) fn such that the expression fn(a1, ..., aN) is equivalent to ((*obj).*pm)(a1,…, aN). fn shall have a nested type result_type that is a synonym for the return type of pm when pm is a pointer to member function.

The simple call wrapper shall define one nested type named result_type as a synonym for Ret, where Ret  is pm’s return type.

The simple call wrapper shall define two nested types named argument_type and result_type as synonyms for T1 and Ret, respectively, when pm is a pointer to member function taking  one argument of type T1, where Ret is pm’s return type.

The simple call wrapper shall define three nested types named first_argument_type, second_argument_type, and result_type as synonyms for T1, T2, and Ret, respectively, when pm is a pointer to member function taking two arguments of types T1 and  T2, where Ret is pm’s return type.

Throws: Nothing unless the evaluation of obj throws.

______________________________________________________________________________________________________________________________

In comparison, the definition of bind allows to use as a second argument not only a pointer to an object or a smart-pointer but also an object itself. If we want to do something like that the proposed definition of mem_fn should be extended.

Is there any reason to limit the to limit the new overload of mem_fn to accept function pointers only? It may be usefull to create an functor that will extend livetime of the object whiel

Also I would rather make the new overload of mem_fn as uniform with bind as possible, so it should:
  - accept any member pointers (function and data pointers)
  - as a second argument accept both object, pointers and reference (via reference_wrapper).
  - intialize the stored copy of the second arguemnt the same way as bind does
 Futhermore I think the return should be definied using INVOKE for the consistency.

I don't really undestrand what you mean by:

Mikhail Semenov

unread,
Jul 20, 2013, 1:12:25 PM7/20/13
to std-pr...@isocpp.org
>I don't really undestrand what you mean by:
>Throws: Nothing unless the evaluation of obj throws.
 
I only meant "unless the evaluation of the second argument throws". The point is that after that may come a copy construction of a smart  pointer, which usually does not throw.
 

 

Jonathan Wakely

unread,
Jul 22, 2013, 7:54:03 AM7/22/13
to std-pr...@isocpp.org


On Saturday, July 20, 2013 5:26:24 PM UTC+1, toma...@gmail.com wrote:

Is there any reason to limit the to limit the new overload of mem_fn to accept function pointers only? It may be usefull to create an functor that will extend livetime of the object whiel


Right, and that's why it should not be an extension to mem_fn.

As I said at https://groups.google.com/a/isocpp.org/d/msg/std-proposals/CxpGVY1APcs/_RYAajMGhcUJ this proposal (which *binds* an object to a member function, or potentially other callable) makes more sense as an extension of std::bind not std::mem_fn, where you would use std::placeholders::all to say that any and all arguments should be forwarded to the target object.


 
Also I would rather make the new overload of mem_fn as uniform with bind as possible, so it should:
  - accept any member pointers (function and data pointers)
  - as a second argument accept both object, pointers and reference (via reference_wrapper).
  - intialize the stored copy of the second arguemnt the same way as bind does
 Futhermore I think the return should be definied using INVOKE for the consistency.

Defining it as an extension to std::bind would make it uniform with bind!
 

toma...@gmail.com

unread,
Jul 22, 2013, 12:26:04 PM7/22/13
to std-pr...@isocpp.org
W dniu poniedziałek, 22 lipca 2013 13:54:03 UTC+2 użytkownik Jonathan Wakely napisał:
On Saturday, July 20, 2013 5:26:24 PM UTC+1, toma...@gmail.com wrote:

Is there any reason to limit the to limit the new overload of mem_fn to accept function pointers only? It may be usefull to create an functor that will extend livetime of the object whiel


Right, and that's why it should not be an extension to mem_fn.

As I said at https://groups.google.com/a/isocpp.org/d/msg/std-proposals/CxpGVY1APcs/_RYAajMGhcUJ this proposal (which *binds* an object to a member function, or potentially other callable) makes more sense as an extension of std::bind not std::mem_fn, where you would use std::placeholders::all to say that any and all arguments should be forwarded to the target object.
 
I miss you point before and I fully agree that extending the bind to support group placeholders: all, maybe from<N> defined as _N, _N+1, .... (may be a hard to choose behavior in case if there are less than N arguments) is the better solution for the problem.
 
Also I would rather make the new overload of mem_fn as uniform with bind as possible, so it should:
  - accept any member pointers (function and data pointers)
  - as a second argument accept both object, pointers and reference (via reference_wrapper).
  - intialize the stored copy of the second arguemnt the same way as bind does
 Futhermore I think the return should be definied using INVOKE for the consistency.

Defining it as an extension to std::bind would make it uniform with bind!
 
 I agree.

Mikhail Semenov

unread,
Jul 22, 2013, 1:37:47 PM7/22/13
to std-pr...@isocpp.org
>Requires: ObjT shall be CopyConstructible.
>And change the the clause:
>Throws: Nothing.
>To something similar to:
>Throws: Nothing unless the selected constructor of ObjT throws.
 
I fully agree with this point.

Mikhail Semenov

unread,
Jul 22, 2013, 1:48:39 PM7/22/13
to std-pr...@isocpp.org
>this proposal (which *binds* an object to a member function, or potentially other callable) makes more sense as an extension of std::bind not std::mem_fn, where you would >use std::placeholders::all to say that any and all arguments should be forwarded to the target object.
 
So, instead of writing std::mem_fn(&A::f, &a), I will have to write std::bind(&A::f, &a, std::placeholders::all).
 
First of all, it's longer, and, secondly, it's ugly.
 
I would not like using bind at all: in general. In all cases, it's better using lambda expressions then. std::bind was good when there were no lambda expressions, now it's function is redundant.
 
 
 

 
 
 

Mikhail Semenov

unread,
Jul 22, 2013, 2:09:22 PM7/22/13
to std-pr...@isocpp.org
>Futhermore I think the return should be definied using INVOKE for the consistency.
I agree with this point. The second argument should allow an object, a pointer to an object, a smart-pointer, etc.

 




Nicol Bolas

unread,
Jul 22, 2013, 3:24:57 PM7/22/13
to std-pr...@isocpp.org


On Monday, July 22, 2013 10:48:39 AM UTC-7, Mikhail Semenov wrote:
>this proposal (which *binds* an object to a member function, or potentially other callable) makes more sense as an extension of std::bind not std::mem_fn, where you would >use std::placeholders::all to say that any and all arguments should be forwarded to the target object.
 
So, instead of writing std::mem_fn(&A::f, &a), I will have to write std::bind(&A::f, &a, std::placeholders::all).
 
First of all, it's longer, and, secondly, it's ugly.

Neither of which is a compelling argument against having it. Especially since it will also work with things that aren't member functions.
Message has been deleted

toma...@gmail.com

unread,
Jul 22, 2013, 4:20:21 PM7/22/13
to std-pr...@isocpp.org


W dniu poniedziałek, 22 lipca 2013 19:48:39 UTC+2 użytkownik Mikhail Semenov napisał:
>this proposal (which *binds* an object to a member function, or potentially other callable) makes more sense as an extension of std::bind not std::mem_fn, where you would >use std::placeholders::all to say that any and all arguments should be forwarded to the target object.
 
So, instead of writing std::mem_fn(&A::f, &a), I will have to write std::bind(&A::f, &a, std::placeholders::all).
 
First of all, it's longer, and, secondly, it's ugly.
 
But if the bind expression would be accepted, you can still use in your codebase and propose to the standard mem_fn with addtional object, definied as:
template<typename R, typename C, typename T>
inline auto mem_fn(R C::* ptr, T&& t)
{
   return std::bind(ptr, std::forward<T>(t), std::placeholders::all);
}
And there will be non need to make separate wording that duplicates the bind semantcis, just forward to them (you agreed with me that I should have nearly the same semantics).
I personalny like the syntax with mem_fn(ptr, t), but I still now thinks the best way to introduce it will be to extend bind and define it in the means of the bind.

 
I would not like using bind at all: in general. In all cases, it's better using lambda expressions then. std::bind was good when there were no lambda expressions, now it's function is redundant.
 
 I would argue with that point. I found the code that uses bind shorter and more readable. Just simple xample:
  std::bind(&amp;foo, _1, expr, ref(a));
  [e = expr, &a] (auto&& arg) -> decltype(auto) { return foo(std::forward<decltype(arg)>(arg), e, a); }
Or to be more precise (sometimes i use the ability to discard trainling argument):
  [e = expr, &a] (auto&& arg, auto&&...) -> decltype(auto) { return foo(std::forward<decltype(arg)>(arg), e, a); }

Mikhail Semenov

unread,
Jul 22, 2013, 5:02:23 PM7/22/13
to std-pr...@isocpp.org
>template<typename R, typename C, typename T>
>inline auto mem_fn(R C::* ptr, T&& t)
>{
>   return std::bind(ptr, std::forward<T>(t), std::placeholders::all);
>}
 
Here we go, another wrapper!
I would rather define the following macro:
 
#define member_delegate(_obj,_f)\
[&](auto&& ... _x) { return ((*_obj)._f)(std::forward<decltype(x)>(x) ...); }
 
The advantage is that it will cope with member-function overloading as well:
class C
{
public:
void f(const &T t);
void f(T&& t);
};
 
T p();
 
C c1;
...
auto fc = member_delegate(c,f);
T z;
fc(z); // the first one is called;
fc(p()); // the second one is called;
 
 
 
 
 

Jonathan Wakely

unread,
Jul 23, 2013, 5:55:28 AM7/23/13
to std-pr...@isocpp.org


On Monday, July 22, 2013 6:48:39 PM UTC+1, Mikhail Semenov wrote:
>this proposal (which *binds* an object to a member function, or potentially other callable) makes more sense as an extension of std::bind not std::mem_fn, where you would >use std::placeholders::all to say that any and all arguments should be forwarded to the target object.
 
So, instead of writing std::mem_fn(&A::f, &a), I will have to write std::bind(&A::f, &a, std::placeholders::all).
 
First of all, it's longer, and, secondly, it's ugly.
 

But it's more flexible than your mem_fn proposal, as it supports the same "forward all arguments" behaviour that you want, but is not limited to member functions and works with all callable types.
 
I would not like using bind at all: in general. In all cases, it's better using lambda expressions then. std::bind was good when there were no lambda expressions, now it's function is redundant.

Why is your mem_fn proposal not also redundant with generic lambda expressions?


Mikhail Semenov

unread,
Jul 23, 2013, 9:40:37 AM7/23/13
to std-pr...@isocpp.org
>Why is your mem_fn proposal not also redundant with generic lambda expressions?
 
You're probably right. But I would prefer member_delegate it to be part of the standard then, instead of defining it every time I want to use it. Another concern is whether the caption [&] will work in all the circumstances.
 


 

Mikhail Semenov

unread,
Jul 23, 2013, 9:42:18 AM7/23/13
to std-pr...@isocpp.org
Sorry I meant the capture [&].

 


 

Sebastian Gesemann

unread,
Jul 24, 2013, 5:47:50 AM7/24/13
to std-pr...@isocpp.org
I'd like to mention another potential optimization that this proposal allows.

On Wed, May 29, 2013 at 10:24 PM, Mikhail Semenov wrote:
> auto af8 = std::mem_fn(&A2::f8, &a); // shorter then writing a bind

Suppose A2::f8 is a virtual function. Then, whenever you use is with
an object a

(a.*pfm)(params...);

the compiler needs to insert code that follows the "vptr" to get the
right function pointer.

But if you want to call this virtual function many times on some
specific object (which does not change its dynamic type), this
proposal could save some time. C++ implementers might use a compiler
extension in this case so that the actual function that will be called
is resolved just once during the creation of the functor.

Cheers!
SG
Reply all
Reply to author
Forward
0 new messages