How to implement an easy_bind() that automagically inserts implied placeholders? *With member pointers*
Your code has two key problems:
- You keep taking the address of the object you want to call a member function on. Once the entity is a pointer, taking the address of it won't do you much good.
- A member function pointer and its first argument obvious have different types. Either you'll need to provide a proper signature of it, you'd extract the first argument type from the member function pointer type, or you leave the corresponding argument type unconstrained and have the type system sort out invalid uses. The latter approach also has the advantage that you could pass reference and smart pointers.
Here is a patched up version of your code which makes it compile:
#include <functional>
#include <type_traits>
#include <utility>
template <std::size_t... Is>
struct indices {};
template <std::size_t N, std::size_t... Is>
struct build_indices
: build_indices<N-1, N-1, Is...> {};
template <std::size_t... Is>
struct build_indices<0, Is...> : indices<Is...> {};
template<int I> struct placeholder{};
namespace std{
template<int I>
struct is_placeholder< ::placeholder<I>> : std::integral_constant<int, I>{};
} // std::
namespace detail{
template<std::size_t... Is, class Ret, class Fn, class... MArgs, class... Args>
auto my_bind(indices<Is...>, Ret (Fn::*f)(MArgs...), Fn *i, Args&&... args)
-> decltype(std::bind(f, i, std::forward<Args>(args)..., placeholder<1 + Is>{}...)){
return std::bind(f, i, std::forward<Args>(args)..., placeholder<1 + Is>{}...);
}
}
template<class Ret, class... FArgs, class Fn, class... MArgs, class... Args>
auto my_bind(std::function<Ret(FArgs...)>, Ret (Fn::*f)(MArgs...), Fn *i, Args&&... args)
-> decltype(detail::my_bind(build_indices<sizeof...(FArgs) - sizeof...(Args)>{}, f, i, std::forward<Args>(args)...)){
return detail::my_bind(build_indices<sizeof...(FArgs) - sizeof...(Args)>{}, f, i, std::forward<Args>(args)...);
}
#include <iostream>
struct tmp{
void testt(int var1, int var2){
std::cout << var1 << " " << var2 << std::endl;
}
};
int main(){
tmp TMP;
auto f3 = my_bind(std::function<void(int, int)>(), &tmp::testt, &TMP);
f3(22, 23);
}
How to implement an easy_bind() that automagically inserts implied placeholders?
With the indices trick and the ability to tell std::bind
about your own placeholder types, here's what I came up with:
#include <functional>
#include <type_traits>
#include <utility>
template<int I> struct placeholder{};
namespace std{
template<int I>
struct is_placeholder< ::placeholder<I>> : std::integral_constant<int, I>{};
} // std::
namespace detail{
template<std::size_t... Is, class F, class... Args>
auto easy_bind(indices<Is...>, F const& f, Args&&... args)
-> decltype(std::bind(f, std::forward<Args>(args)..., placeholder<Is + 1>{}...))
{
return std::bind(f, std::forward<Args>(args)..., placeholder<Is + 1>{}...);
}
} // detail::
template<class R, class... FArgs, class... Args>
auto easy_bind(std::function<R(FArgs...)> const& f, Args&&... args)
-> decltype(detail::easy_bind(build_indices<sizeof...(FArgs) - sizeof...(Args)>{}, f, std::forward<Args>(args)...))
{
return detail::easy_bind(build_indices<sizeof...(FArgs) - sizeof...(Args)>{}, f, std::forward<Args>(args)...);
}
Live example.
Take note that I require the function argument to easy_bind
to be either of type std::function
, or convertible to it, so that I have a definite signature available.
How to implement an easy_bind() that automagically inserts implied placeholders?
With the indices trick and the ability to tell std::bind
about your own placeholder types, here's what I came up with:
#include <functional>
#include <type_traits>
#include <utility>
template<int I> struct placeholder{};
namespace std{
template<int I>
struct is_placeholder< ::placeholder<I>> : std::integral_constant<int, I>{};
} // std::
namespace detail{
template<std::size_t... Is, class F, class... Args>
auto easy_bind(indices<Is...>, F const& f, Args&&... args)
-> decltype(std::bind(f, std::forward<Args>(args)..., placeholder<Is + 1>{}...))
{
return std::bind(f, std::forward<Args>(args)..., placeholder<Is + 1>{}...);
}
} // detail::
template<class R, class... FArgs, class... Args>
auto easy_bind(std::function<R(FArgs...)> const& f, Args&&... args)
-> decltype(detail::easy_bind(build_indices<sizeof...(FArgs) - sizeof...(Args)>{}, f, std::forward<Args>(args)...))
{
return detail::easy_bind(build_indices<sizeof...(FArgs) - sizeof...(Args)>{}, f, std::forward<Args>(args)...);
}
Live example.
Take note that I require the function argument to easy_bind
to be either of type std::function
, or convertible to it, so that I have a definite signature available.
Packing an object, its method to call and arguments to call it with into a single object for invoking it later
That's the classic use case for std::bind
and std::function
:
#include <functional>
#include <vector>
using namespace std::placeholders; // for _1, _2, ...
std::vector<std::function<int(double, char)>> v;
Foo x;
Bar y;
v.emplace_back(std::bind(&Foo::f, &x, _1, _2)); // int Foo::f(double, char)
v.emplace_back(std::bind(&Bar::g, &y, _2, true, _1)); // int Bar::g(char, bool, double)
v.emplace_bacK(some_free_function); // int some_free_function(double, char)
To use:
for (auto & f : v) { sum += f(1.5, 'a'); }
Nested bind to member, need a pointer, got a reference. What do?
The compiler error is due to the fact that std::map
const'ifies the key type, so that the value_type
of map_t
is not std::pair<long, std::unique_ptr<foo> >
but rather std::pair<long const, std::unique_ptr<foo> >
. To avoid such errors prefer using map_t::value_type
. The following change fixes the error:
... std::bind(&map_t::value_type::second, std::placeholders::_1) ...
In C++11 you can simplify it to:
for(auto const& kv : foo_map_)
bar_.DoWork(&*kv.second);
Or, using std::for_each
and C++11 lambda:
for_each(foo_map_.begin(), foo_map_.end(),
[&bar_](map_t::value_type const& kv) { bar_.DoWork(&*kv.second); });
Syntax sugar for signal slot
Is it possible in modern C++ to implement such functionality in, for example, C# way? [...]
No, that's not possible in C++. The syntax for taking the address of a member function requires qualifying the function name with the class name (i.e. &MyClassName::myMethodName
).
If you don't want to specify the class name, one possibility is to use lambdas. In particular, if you can afford a C++14 compiler, generic lambdas allow writing:
mySignal.connect([this] (auto x) -> { myMethodName(x) });
Sadly, you can't get much terser than this. You can use default lambda capture to save some syntactic noise:
mySignal.connect([&] (auto x) -> { myMethodName(x) });
However, Scott Meyers warns against the pitfalls of default lambda capture modes in his new book Effective Modern C++. From the readability point of view, I'm not sure this improves things a lot compared to your first option.
Besides, things soon become awkward if you want your lambda to perfectly forward its argument(s) to myMethodName
:
mySignal.connect([&] (auto&& x) -> { myMethodName(std::forward<decltype(x)>(x)) });
If you don't mind macros (I usually do), you can employ a preprocessor-based solution as suggested by Quentin in their answer. However, I would prefer using a perfect-forwarding lambda in that case:
#define SLOT(name) \
[this] (auto&&... args) { name (std::forward<decltype(args)>(args)...); }
Which you could use like so:
e.connect(SLOT(foo));
Here is a live demo on Coliru.
How to implement a std::function with operator= that can check if its rhs has same signature
Cppreference says about operator=
:
Sets the target of *this to the callable f, as if by executing function(std::forward(f)).swap(*this);. This operator does not participate in overload resolution unless f is Callable for argument types Args... and return type R.
This can be easily checked with std::is_invocable_r
helper:
#include <type_traits>
template <class>
class function {};
template <class R, class... Args>
class function<R(Args...)> {
public:
template <typename F, typename x = std::enable_if_t<
std::is_invocable_r<R, F, Args...>::value>>
function& operator=(F&& f) {
// logic...
return *this;
}
};
#include <functional>
#include <string>
void bar1(std::string) {}
void bar2(int) {}
void bar3(float) {}
int bar4(int) { return 0; }
int main(int argc, char** argv) {
//std::function<void(int)> f;
function<void(int)> f;
// f = bar1; ERROR
f = bar2;
f = bar3;
f = bar4;
return 0;
}
I am using the SFINAE version with an extra template argument as I find it most clear but return-value-based can be used too.
Same as for std::function
, this is really forgiving - extra return values in case of R=void
are ignored, implicit conversions are enabled. This matches what std::is_invocable_r
allows.
Wrapping a non-static method into std::function with this parameter bound using as little code as possible
When calling a member function through
->*
operator, you have to use parenthesis:(target->*method)(std::forward<Arguments>(args)...);
^ ^When calling a member function through a pointer to
const
(you do, noteconst T*
), that member function has to beconst
qualified:void print(float a, int b) const
^^^^^Is there a way to specify explicitly that Method is a member method of T in the declaration of Method itself?
template <class T>
void connect(const T* target, void (T::*method)(Arguments...) const)
member function pointer with variadic templates
One approach is to use partial specialization:
template<typename> class DelegateManager;
template<typename FuncRetType,typename... FuncParams>
class DelegateManager<DelegateInfoPack<FuncRetType,FuncParams...>>
{
template<typename UserClass>
void BindDelegate(_FuncRetType(UserClass::*fp)(FuncParams...))
{
}
};
Another approach is to have a class which generates the appropriate function type
template <typename FuncRetType,typename FuncParams>
struct FunctionPointer;
template <typename FuncRetType,typename...ARGS>
struct FunctionPointer<FuncRetType,FunctionParamsPack<ARGS...>> {
typedef FuncRetType (Type)(ARGS...);
};
Then use that in your BindDelegate member function:
template<typename UserClass>
void
BindDelegate(
typename FunctionPointer<_FuncRetType,_FuncParams>::Type UserClass::*fp
)
{ ... }
Or maybe even put this into your DelegateInfoPack class:
template<typename FuncRetType,typename... FuncParams>
struct DelegateInfoPack {
.
.
.
typedef FuncRetType (_FuncType)(FuncParams...);
};
and use that in your DelegateManager
template<typename DelegateInfoPack>
struct DelegateManager
{
.
.
.
typedef typename DelegateInfoPack::_FuncType _FuncType;
template<typename UserClass>
void BindDelegate(_FuncType UserClass::*fp)
{
}
};
Related Topics
What Does the |= Operator Mean in C++
What Is a C++11 Extension [-Wc++11-Extensions]
Returning VS. Using a Reference Parameter
In C++ How Is Function Overloading Typically Implemented
Getopt Fails to Detect Missing Argument for Option
Writing X264 from Opencv 3 with Ffmpeg on Linux
What's the Real Use of Using N[C-'0']
How to Find The Full Path of The C++ Linux Program from Within
How to Sort C++ Array in Asc and Desc Mode
Extern "C" Linkage Inside C++ Namespace
Does Insertion to Stl Map Invalidate Other Existing Iterator
How to Add Code at the Entry of Every Function
Std::Lower_Bound Slower for Std::Vector Than Std::Map::Find
Template Specialization for Multiple Types
Why Can Template Instances Not Be Deduced in 'Std::Reference_Wrapper'S