Except you could just do `std::bind(std::mem_fn(&A2::f8), &a)`, which is hardly more arduous.
#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)...);
}
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):
By the way, in GCC (C++) in debug mode bind is pretty slow, but that's an implementation issue.
Jonathan,I don't think it is completely pointless. Most of the time we run our code in debug mode.
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.
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.
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.
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.
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!
>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.
>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.
>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.