Member function passed as std::function to template, binding all params - c++

I have started building the permission management library,
the basic idea is that you have some sort of configuration read from a file and based on that you can execute a functional object which will be wrapping "allow" and "restrict" functions.
The code so far is divided into few parts
I have a permission manager which says if given "std::string" is able to be executed or not:
class PermissionManager {
public:
virtual bool canAccess(std::string resource) {return true;};
};
Next, I have the actual wrapper on the function:
template <typename FuncT>
class PermissionFunction {
private:
FuncT m_restrict;
FuncT m_allow;
PermissionManager *m_pManager;
std::string m_resource;
public:
PermissionFunction(const PermissionFunction&) = delete;
PermissionFunction& operator=(const PermissionFunction&) = delete;
PermissionFunction(FuncT r, FuncT a, PermissionManager *man, std::string res)
: m_restrict(r), m_allow(a), m_pManager(man), m_resource(res){
}
template<typename ...ARG>
typename std::result_of<FuncT(ARG&&...)>::type operator()(ARG&&... args){
if(m_pManager->canAccess(m_resource)){
return m_allow(std::forward<ARG>(args)...);
} else {
return m_restrict(std::forward<ARG>(args)...);
}
}
};
So, the usage is something like:
PermissionManager tpm{};
std::function<void(int)> testRestrict = [](int a){std::cout << "Restrict" << std::endl;};
std::function<void(int)> testAllow = [](int a){std::cout << "Allow" << std::endl;};
PermissionFunction<decltype(testRestrict)> testPerm(testRestrict, testAllow, &tpm, "hi");
for(int i = 0; i <10; i++){
testPerm(i);
}
It works really nice for the non member std::functions, however when I want to define it with a member function it gets very messy:
class test {
public:
void testato(int i){
std::cout << i << std::endl;
}
PermissionManager perm{};
PermissionFunction<std::function<void(int)>>
permf{
std::bind(&test::testato, this, std::placeholders::_1),
std::bind(&test::testato, this, std::placeholders::_1),
&perm, "hi"};
};
I am wondering if there is any way to shorten up the usage for the member variable types, I was thinking about using the template for that as well but I am not sure how to use std bind with veriadic template parameters and it has to work for any function type.
The goal would be to have the function declaration similar to the one with the std::functions in the example given, so that I can define the member object in this maner:
some_template<decltype(member_f)>
wrapper_member{member_f, member_f, &tpm, "resource"}
Where member_f is an actual member function of a class. Ideally the type would be deduced but I think it would also be acceptable to repeat it in such manner:
some_template<return_t(args_t)>
wrapper_member{member_f, member_f, &tpm, "resource"}

C++20 introduces std::bind_front which binds arguments only to the leading parameters, and so doesn't require the use of placeholder objects. It could be used to make your code more concise.
PermissionFunction<std::function<void(int)>> permf{
std::bind_front(&test::testato, this),
std::bind_front(&test::testato, this),
&perm, "hi"};
A possible C++17 implementation:
#include <tuple>
#include <utility>
template <typename F, typename... Xs>
auto bind_front(F&& f, Xs&&... xs)
{
return [
f = std::forward<F>(f),
xs = std::make_tuple(std::forward<Xs>(xs)...)](auto&&... ys) -> decltype(auto)
{
return std::apply(
f,
std::tuple_cat(xs, std::forward_as_tuple(std::forward<decltype(ys)>(ys)...)));
};
}

Related

Lambda function in another lambda function, C++; How can I make this code work? [duplicate]

Is it possible to pass a lambda function as a function pointer? If so, I must be doing something incorrectly because I am getting a compile error.
Consider the following example
using DecisionFn = bool(*)();
class Decide
{
public:
Decide(DecisionFn dec) : _dec{dec} {}
private:
DecisionFn _dec;
};
int main()
{
int x = 5;
Decide greaterThanThree{ [x](){ return x > 3; } };
return 0;
}
When I try to compile this, I get the following compilation error:
In function 'int main()':
17:31: error: the value of 'x' is not usable in a constant expression
16:9: note: 'int x' is not const
17:53: error: no matching function for call to 'Decide::Decide(<brace-enclosed initializer list>)'
17:53: note: candidates are:
9:5: note: Decide::Decide(DecisionFn)
9:5: note: no known conversion for argument 1 from 'main()::<lambda()>' to 'DecisionFn {aka bool (*)()}'
6:7: note: constexpr Decide::Decide(const Decide&)
6:7: note: no known conversion for argument 1 from 'main()::<lambda()>' to 'const Decide&'
6:7: note: constexpr Decide::Decide(Decide&&)
6:7: note: no known conversion for argument 1 from 'main()::<lambda()>' to 'Decide&&'
That's one heck of an error message to digest, but I think what I'm getting out of it is that the lambda cannot be treated as a constexpr so therefore I cannot pass it as a function pointer? I've tried making x constexpr as well, but that doesn't seem to help.
A lambda can only be converted to a function pointer if it does not capture, from the draft C++11 standard section 5.1.2 [expr.prim.lambda] says (emphasis mine):
The closure type for a lambda-expression with no lambda-capture has a
public non-virtual non-explicit const conversion function to pointer
to function having the same parameter and return types as the closure
type’s function call operator. The value returned by this conversion
function shall be the address of a function that, when invoked, has
the same effect as invoking the closure type’s function call operator.
Note, cppreference also covers this in their section on Lambda functions.
So the following alternatives would work:
typedef bool(*DecisionFn)(int);
Decide greaterThanThree{ []( int x ){ return x > 3; } };
and so would this:
typedef bool(*DecisionFn)();
Decide greaterThanThree{ [](){ return true ; } };
and as 5gon12eder points out, you can also use std::function, but note that std::function is heavy weight, so it is not a cost-less trade-off.
Shafik Yaghmour's answer correctly explains why the lambda cannot be passed as a function pointer if it has a capture. I'd like to show two simple fixes for the problem.
Use std::function instead of raw function pointers.
This is a very clean solution. Note however that it includes some additional overhead for the type erasure (probably a virtual function call).
#include <functional>
#include <utility>
struct Decide
{
using DecisionFn = std::function<bool()>;
Decide(DecisionFn dec) : dec_ {std::move(dec)} {}
DecisionFn dec_;
};
int
main()
{
int x = 5;
Decide greaterThanThree { [x](){ return x > 3; } };
}
Use a lambda expression that doesn't capture anything.
Since your predicate is really just a boolean constant, the following would quickly work around the current issue. See this answer for a good explanation why and how this is working.
// Your 'Decide' class as in your post.
int
main()
{
int x = 5;
Decide greaterThanThree {
(x > 3) ? [](){ return true; } : [](){ return false; }
};
}
Lambda expressions, even captured ones, can be handled as a function pointer (pointer to member function).
It is tricky because an lambda expression is not a simple function. It is actually an object with an operator().
When you are creative, you can use this!
Think of an "function" class in style of std::function.
If you save the object you also can use the function pointer.
To use the function pointer, you can use the following:
int first = 5;
auto lambda = [=](int x, int z) {
return x + z + first;
};
int(decltype(lambda)::*ptr)(int, int)const = &decltype(lambda)::operator();
std::cout << "test = " << (lambda.*ptr)(2, 3) << std::endl;
To build a class that can start working like a "std::function", first you need a class/struct than can store object and function pointer. Also you need an operator() to execute it:
// OT => Object Type
// RT => Return Type
// A ... => Arguments
template<typename OT, typename RT, typename ... A>
struct lambda_expression {
OT _object;
RT(OT::*_function)(A...)const;
lambda_expression(const OT & object)
: _object(object), _function(&decltype(_object)::operator()) {}
RT operator() (A ... args) const {
return (_object.*_function)(args...);
}
};
With this you can now run captured, non-captured lambdas, just like you are using the original:
auto capture_lambda() {
int first = 5;
auto lambda = [=](int x, int z) {
return x + z + first;
};
return lambda_expression<decltype(lambda), int, int, int>(lambda);
}
auto noncapture_lambda() {
auto lambda = [](int x, int z) {
return x + z;
};
return lambda_expression<decltype(lambda), int, int, int>(lambda);
}
void refcapture_lambda() {
int test;
auto lambda = [&](int x, int z) {
test = x + z;
};
lambda_expression<decltype(lambda), void, int, int>f(lambda);
f(2, 3);
std::cout << "test value = " << test << std::endl;
}
int main(int argc, char **argv) {
auto f_capture = capture_lambda();
auto f_noncapture = noncapture_lambda();
std::cout << "main test = " << f_capture(2, 3) << std::endl;
std::cout << "main test = " << f_noncapture(2, 3) << std::endl;
refcapture_lambda();
system("PAUSE");
return 0;
}
This code works with VS2015
Update 04.07.17:
template <typename CT, typename ... A> struct function
: public function<decltype(&CT::operator())(A...)> {};
template <typename C> struct function<C> {
private:
C mObject;
public:
function(const C & obj)
: mObject(obj) {}
template<typename... Args> typename
std::result_of<C(Args...)>::type operator()(Args... a) {
return this->mObject.operator()(a...);
}
template<typename... Args> typename
std::result_of<const C(Args...)>::type operator()(Args... a) const {
return this->mObject.operator()(a...);
}
};
namespace make {
template<typename C> auto function(const C & obj) {
return ::function<C>(obj);
}
}
int main(int argc, char ** argv) {
auto func = make::function([](int y, int x) { return x*y; });
std::cout << func(2, 4) << std::endl;
system("PAUSE");
return 0;
}
Capturing lambdas cannot be converted to function pointers, as this answer pointed out.
However, it is often quite a pain to supply a function pointer to an API that only accepts one. The most often cited method to do so is to provide a function and call a static object with it.
static Callable callable;
static bool wrapper()
{
return callable();
}
This is tedious. We take this idea further and automate the process of creating wrapper and make life much easier.
#include<type_traits>
#include<utility>
template<typename Callable>
union storage
{
storage() {}
std::decay_t<Callable> callable;
};
template<int, typename Callable, typename Ret, typename... Args>
auto fnptr_(Callable&& c, Ret (*)(Args...))
{
static bool used = false;
static storage<Callable> s;
using type = decltype(s.callable);
if(used)
s.callable.~type();
new (&s.callable) type(std::forward<Callable>(c));
used = true;
return [](Args... args) -> Ret {
return Ret(s.callable(std::forward<Args>(args)...));
};
}
template<typename Fn, int N = 0, typename Callable>
Fn* fnptr(Callable&& c)
{
return fnptr_<N>(std::forward<Callable>(c), (Fn*)nullptr);
}
And use it as
void foo(void (*fn)())
{
fn();
}
int main()
{
int i = 42;
auto fn = fnptr<void()>([i]{std::cout << i;});
foo(fn); // compiles!
}
Live
This is essentially declaring an anonymous function at each occurrence of fnptr.
Note that invocations of fnptr overwrite the previously written callable given callables of the same type. We remedy this, to a certain degree, with the int parameter N.
std::function<void()> func1, func2;
auto fn1 = fnptr<void(), 1>(func1);
auto fn2 = fnptr<void(), 2>(func2); // different function
Not a direct answer, but a slight variation to use the "functor" template pattern to hide away the specifics of the lambda type and keeps the code nice and simple.
I was not sure how you wanted to use the decide class so I had to extend the class with a function that uses it. See full example here: https://godbolt.org/z/jtByqE
The basic form of your class might look like this:
template <typename Functor>
class Decide
{
public:
Decide(Functor dec) : _dec{dec} {}
private:
Functor _dec;
};
Where you pass the type of the function in as part of the class type used like:
auto decide_fc = [](int x){ return x > 3; };
Decide<decltype(decide_fc)> greaterThanThree{decide_fc};
Again, I was not sure why you are capturing x it made more sense (to me) to have a parameter that you pass in to the lambda) so you can use like:
int result = _dec(5); // or whatever value
See the link for a complete example
A shortcut for using a lambda with as a C function pointer is this:
"auto fun = +[](){}"
Using Curl as exmample (curl debug info)
auto callback = +[](CURL* handle, curl_infotype type, char* data, size_t size, void*){ //add code here :-) };
curl_easy_setopt(curlHande, CURLOPT_VERBOSE, 1L);
curl_easy_setopt(curlHande,CURLOPT_DEBUGFUNCTION,callback);
A simular answer but i made it so you don't have to specify the type of returned pointer (note that the generic version requires C++20):
#include <iostream>
template<typename Function>
struct function_traits;
template <typename Ret, typename... Args>
struct function_traits<Ret(Args...)> {
typedef Ret(*ptr)(Args...);
};
template <typename Ret, typename... Args>
struct function_traits<Ret(*const)(Args...)> : function_traits<Ret(Args...)> {};
template <typename Cls, typename Ret, typename... Args>
struct function_traits<Ret(Cls::*)(Args...) const> : function_traits<Ret(Args...)> {};
using voidfun = void(*)();
template <typename F>
voidfun lambda_to_void_function(F lambda) {
static auto lambda_copy = lambda;
return []() {
lambda_copy();
};
}
// requires C++20
template <typename F>
auto lambda_to_pointer(F lambda) -> typename function_traits<decltype(&F::operator())>::ptr {
static auto lambda_copy = lambda;
return []<typename... Args>(Args... args) {
return lambda_copy(args...);
};
}
int main() {
int num;
void(*foo)() = lambda_to_void_function([&num]() {
num = 1234;
});
foo();
std::cout << num << std::endl; // 1234
int(*bar)(int) = lambda_to_pointer([&](int a) -> int {
num = a;
return a;
});
std::cout << bar(4321) << std::endl; // 4321
std::cout << num << std::endl; // 4321
}
Here is another variation of the solution. C++14 (can be turned into C++11) Supports return values, non-copyable and mutable lambdas. If mutable lambdas not needed, can be even shorter by removing specialization matching non-const version and embedding impl_impl.
For those who wonder, it works because each lambda is unique (is distinct class) and thus invocation of to_f generates unique for this lambda static and corresponding C-style function which can access it.
template <class L, class R, class... Args> static auto impl_impl(L l) {
static_assert(!std::is_same<L, std::function<R(Args...)>>::value,
"Only lambdas are supported, it is unsafe to use "
"std::function or other non-lambda callables");
static L lambda_s = std::move(l);
return +[](Args... args) -> R { return lambda_s(args...); };
}
template <class L>
struct to_f_impl : public to_f_impl<decltype(&L::operator())> {};
template <class ClassType, class R, class... Args>
struct to_f_impl<R (ClassType::*)(Args...) const> {
template <class L> static auto impl(L l) {
return impl_impl<L, R, Args...>(std::move(l));
}
};
template <class ClassType, class R, class... Args>
struct to_f_impl<R (ClassType::*)(Args...)> {
template <class L> static auto impl(L l) {
return impl_impl<L, R, Args...>(std::move(l));
}
};
template <class L> auto to_f(L l) { return to_f_impl<L>::impl(std::move(l)); }
Note, this also tend to work for other callable objects like std::function but it would be better if it didn't work because unlike lambdas, std::function like objects do not generate unique type so inner template and its inner static will be reused for/shared by all functions with same signature, which most probably is not what we want from it. I've specifically disallowed std::function but there exist more which I don't know how to disallow in generic way.
While the template approach is clever for various reasons, it is important to remember the lifecycle of the lambda and the captured variables. If any form of a lambda pointer is is going to be used and the lambda is not a downward continuation, then only a copying [=] lambda should used. I.e., even then, capturing a pointer to a variable on the stack is UNSAFE if the lifetime of those captured pointers (stack unwind) is shorter than the lifetime of the lambda.
A simpler solution for capturing a lambda as a pointer is:
auto pLamdba = new std::function<...fn-sig...>([=](...fn-sig...){...});
e.g., new std::function<void()>([=]() -> void {...}
Just remember to later delete pLamdba so ensure that you don't leak the lambda memory.
Secret to realize here is that lambdas can capture lambdas (ask yourself how that works) and also that in order for std::function to work generically the lambda implementation needs to contain sufficient internal information to provide access to the size of the lambda (and captured) data (which is why the delete should work [running destructors of captured types]).
As it was mentioned by the others you can substitute Lambda function instead of function pointer. I am using this method in my C++ interface to F77 ODE solver RKSUITE.
//C interface to Fortran subroutine UT
extern "C" void UT(void(*)(double*,double*,double*),double*,double*,double*,
double*,double*,double*,int*);
// C++ wrapper which calls extern "C" void UT routine
static void rk_ut(void(*)(double*,double*,double*),double*,double*,double*,
double*,double*,double*,int*);
// Call of rk_ut with lambda passed instead of function pointer to derivative
// routine
mathlib::RungeKuttaSolver::rk_ut([](double* T,double* Y,double* YP)->void{YP[0]=Y[1]; YP[1]= -Y[0];}, TWANT,T,Y,YP,YMAX,WORK,UFLAG);

Forwarding member function arguments

Thing simple enough, I want to forward the call of a member function, along with its arguments, as described in the following snippet.
Please note that this is not a duplicate of this question, nor this one.
#include <iostream>
#include <functional>
template<class Function, class ... Args>
auto forward_args(Function&& f, Args&& ... args)
{
return f(std::forward<Args>(args)...);
}
int f(int i) { return i; }
struct A {
int get(int i) const { return i; }
};
int main()
{
std::cout << forward_args(f, 2) << std::endl; //ok
A a;
//std::cout << forward_args(&A::get, a, 2) << std::endl; //ko
static auto wrong_wrapper = &A::get;
//std::cout << forward_args(wrong_wrapper, a, 2) << std::endl; //ko again
static std::function<int (const A&, int)> wrapper = &A::get;
std::cout << forward_args(wrapper, a, 2) << std::endl;
}
The commented lines in the main function don't compile (g++ 10.2.0 -- error: must use ‘.*’ or ‘->*’ to call pointer-to-member function in ‘f (...)’, e.g. ‘(... ->* f) (...)’)
I don't quite understand what the compiler is trying to tell me, considering the last cll with the std::function wrapper does work. And, beside fixing the code, I'd also like to know why it doesn't work.
Calling a member function through pointer-to-member still requires this pointer, as in usual (direct) invocations. Simply put, you could succeeded calling A::get() like
static auto wrong_wrapper = &A::get;
(a.*wrong_wrapper)(2);
but what you got after forward_args was instantiated is
A::get(a, 2);
which is not the correct syntax in its nature.
Solution
As it has been already said in the comments section, if you are allowed to use C++17, employ std::invoke. If you aren't, you can work it around using std::reference_wrapper, which accepts any callable type.
template<class Function, class ... Args>
auto forward_args(Function f, Args&& ... args)
{
return std::ref(f)(std::forward<Args>(args)...);
}
I don't forward f here because std::reference_wrapper requires that the object passed is not an rval.
UPD:
Don't forget to specify the trailing return type of forward_args if you use C++11
template<class Function, class ... Args>
auto forward_args(Function f, Args&& ... args) -> decltype(std::ref(f)(std::forward<Args>(args)...))
{
return std::ref(f)(std::forward<Args>(args)...);
}
std::function works because it uses std::invoke which handles calling pointer to member function.
As the solution you could write:
template<class Function, class ... Args>
auto forward_args(Function&& f, Args&& ... args) {
return std::invoke(std::forward<Function>(f), std::forward<Args>(args)...);
}
Syntax for calling member function for an object are:
obj.memberFunction();
obj->memberFunction();
or if you have a pointer to member function:
using Ptr = int (A::*)(int) const;
Ptr p = &A::get;
A a;
(a.*p)(1); // [1]
(obj.*memberFuncPtr)(args...);
the line [1] is valid syntax for calling member function pointed by a pointer. In your case you try A::get(a,2) which is just not valid and cannot work.
Alright, first thing, I still don't understand why forward_args(&A::get, a, 2) doesn't work. Part of the answer was "you need this", but I actually provide it with the second parameter, right ? How is that different from the std::function wrapper ?
On the other hand, while the workarounds proposed in above answer work on the snippet, I actually simplified my original problem too much. I actually need to launch tasks asynchronously, in the following code
thread safety has been removed
yeah, I want to pack all calls in a single data structure, namely tasks, which is wy I start building up wrappers
I don't understand how I can use the proposed solutions to the code below.
#include <iostream>
#include <future>
#include <functional>
#include <queue>
std::queue<std::function<void()>> tasks;
template<class Function, class ... Args>
auto enqueue(Function&& f, Args&& ... args) -> std::future<decltype(f(args...))>
{
std::function<decltype(f(args...))()> func = std::bind(std::forward<Function>(f), std::forward<Args>(args)...);
auto task_ptr = std::make_shared<std::packaged_task<decltype(f(args...))()>>(func);
std::function<void()> wrapper = [task_ptr]() //wrapper to match types of 'tasks'... ugly
{
(*task_ptr)();
};
tasks.push(wrapper);
return task_ptr->get_future();
}
void indep() {}
struct A {
int get(int i) const { return i; }
};
int main()
{
enqueue(indep);
A a;
//enqueue(&A::get, a, 2); //wrong
static auto wrapper_wrong = &A::get;
//enqueue(wrapper_wrong, a, 2); //wrong again
static std::function<int(const A&,int)> wrapper = &A::get;
enqueue(wrapper, a, 2); //ok
static auto autoptr = std::mem_fn(&A::get);
enqueue(autoptr, a, 2); //ok again
}

How to use std::bind with the standard library and save the return type?

I'm working on a class that schedules functions by binding them in a queue like this:
std::queue <void()> q;
template<typename R,typename... ArgsT>
void
schedule(R& fn, ArgsT&... args)
{
q.push(std::bind(fn, std::forward<ArgsT>(args)...) );
};
template<typename R,typename... ArgsT>
void
schedule(R&& fn, ArgsT&&... args)
{
q.push(std::bind(fn, std::forward<ArgsT>(args)...) );
};
As you see I made the type in the queue void() to make it hold any type of function objects but now I can't get the return when I execute it. What should I do to solve this?
Note: I don't want to use an external library like boost and I don't know what kind of function the user will pass it.
Note: I don't want to use an external library like boost and I don't
know what's the kind of function the user will pass it.
What I usually do in this case is I use a base class (from Command pattern) in my queue, and then have two implementations, the one wrapping the bind, and the other (also wrapping the bind) exposing a function that allows getting the return value.
Here is an example of the returning specialization (at last):
#include <iostream>
#include <functional>
#include <memory>
struct ACmd
{
virtual void exec() = 0;
virtual ~ACmd(){}
};
template <class F>
struct Cmd;
template <class R, class ... Args>
struct Cmd<R(Args...)> : ACmd
{
R result_;
std::function<R()> func_;
template <class F>
Cmd(F&& func, Args&&... args): result_(), func_()
{
auto f = std::bind(std::forward<F>(func), std::forward<Args>(args)...);
func_ = [f](){
return f();
};
}
virtual void exec(){
result_ = func_();
}
const R& getResult() const {return result_;}
};
// Make function for convenience, could return by value or ptr -
// - your choice
template <class R, class F, class ...Args>
Cmd<R(Args...)>* cmd(F&& func, Args&&... args)
{
return new Cmd<R(Args...)>(func, std::forward<Args>(args)...);
}
//... And overload for void...
int foo(int arg) {
return arg;
}
int main() {
auto x = cmd<int>(foo, 10);
x->exec();
std::cout << x->getResult() << std::endl;
return 0;
}
The result of the execution of each element in the queue, it is void, you have already defined it as such. If the functions passed in are required to return a value, then you would need to limit the type(s) returned to a fixed type, use utilities such as std::any, std::variant or some covariant types (possible with a std::unique_ptr or std::shared_ptr).
The simplest is to fix the return type (at compile time);
template <typename R>
using MQ = std::queue<std::function<R()>>;
MQ<int> q;
See the sample below.
The queue declaration needs to be a queue of objects, such as std::function objects. The return value from a bind can be assigned to a function and then used as expected.
std::function is a polymorphic function wrapper, it implements type erasure patterns akin to any, but is specifically designed for functions and other callable objects.
By way of example;
template <typename R>
using MQ = std::queue<std::function<R()>>;
MQ<int> q;
template<typename R,typename... ArgsT>
void
schedule(R&& fn, ArgsT&&... args)
{
q.push(std::bind(std::forward<R>(fn), std::forward<ArgsT>(args)...) );
};
int main()
{
schedule([](int a) { std::cout << "function called" << std::endl; return a; }, 42);
std::cout << q.front()() << std::endl;
}

Semantically, are lambdas real functions in C++? How can I point to a lambda expression to prove it? [duplicate]

Is it possible to pass a lambda function as a function pointer? If so, I must be doing something incorrectly because I am getting a compile error.
Consider the following example
using DecisionFn = bool(*)();
class Decide
{
public:
Decide(DecisionFn dec) : _dec{dec} {}
private:
DecisionFn _dec;
};
int main()
{
int x = 5;
Decide greaterThanThree{ [x](){ return x > 3; } };
return 0;
}
When I try to compile this, I get the following compilation error:
In function 'int main()':
17:31: error: the value of 'x' is not usable in a constant expression
16:9: note: 'int x' is not const
17:53: error: no matching function for call to 'Decide::Decide(<brace-enclosed initializer list>)'
17:53: note: candidates are:
9:5: note: Decide::Decide(DecisionFn)
9:5: note: no known conversion for argument 1 from 'main()::<lambda()>' to 'DecisionFn {aka bool (*)()}'
6:7: note: constexpr Decide::Decide(const Decide&)
6:7: note: no known conversion for argument 1 from 'main()::<lambda()>' to 'const Decide&'
6:7: note: constexpr Decide::Decide(Decide&&)
6:7: note: no known conversion for argument 1 from 'main()::<lambda()>' to 'Decide&&'
That's one heck of an error message to digest, but I think what I'm getting out of it is that the lambda cannot be treated as a constexpr so therefore I cannot pass it as a function pointer? I've tried making x constexpr as well, but that doesn't seem to help.
A lambda can only be converted to a function pointer if it does not capture, from the draft C++11 standard section 5.1.2 [expr.prim.lambda] says (emphasis mine):
The closure type for a lambda-expression with no lambda-capture has a
public non-virtual non-explicit const conversion function to pointer
to function having the same parameter and return types as the closure
type’s function call operator. The value returned by this conversion
function shall be the address of a function that, when invoked, has
the same effect as invoking the closure type’s function call operator.
Note, cppreference also covers this in their section on Lambda functions.
So the following alternatives would work:
typedef bool(*DecisionFn)(int);
Decide greaterThanThree{ []( int x ){ return x > 3; } };
and so would this:
typedef bool(*DecisionFn)();
Decide greaterThanThree{ [](){ return true ; } };
and as 5gon12eder points out, you can also use std::function, but note that std::function is heavy weight, so it is not a cost-less trade-off.
Shafik Yaghmour's answer correctly explains why the lambda cannot be passed as a function pointer if it has a capture. I'd like to show two simple fixes for the problem.
Use std::function instead of raw function pointers.
This is a very clean solution. Note however that it includes some additional overhead for the type erasure (probably a virtual function call).
#include <functional>
#include <utility>
struct Decide
{
using DecisionFn = std::function<bool()>;
Decide(DecisionFn dec) : dec_ {std::move(dec)} {}
DecisionFn dec_;
};
int
main()
{
int x = 5;
Decide greaterThanThree { [x](){ return x > 3; } };
}
Use a lambda expression that doesn't capture anything.
Since your predicate is really just a boolean constant, the following would quickly work around the current issue. See this answer for a good explanation why and how this is working.
// Your 'Decide' class as in your post.
int
main()
{
int x = 5;
Decide greaterThanThree {
(x > 3) ? [](){ return true; } : [](){ return false; }
};
}
Lambda expressions, even captured ones, can be handled as a function pointer (pointer to member function).
It is tricky because an lambda expression is not a simple function. It is actually an object with an operator().
When you are creative, you can use this!
Think of an "function" class in style of std::function.
If you save the object you also can use the function pointer.
To use the function pointer, you can use the following:
int first = 5;
auto lambda = [=](int x, int z) {
return x + z + first;
};
int(decltype(lambda)::*ptr)(int, int)const = &decltype(lambda)::operator();
std::cout << "test = " << (lambda.*ptr)(2, 3) << std::endl;
To build a class that can start working like a "std::function", first you need a class/struct than can store object and function pointer. Also you need an operator() to execute it:
// OT => Object Type
// RT => Return Type
// A ... => Arguments
template<typename OT, typename RT, typename ... A>
struct lambda_expression {
OT _object;
RT(OT::*_function)(A...)const;
lambda_expression(const OT & object)
: _object(object), _function(&decltype(_object)::operator()) {}
RT operator() (A ... args) const {
return (_object.*_function)(args...);
}
};
With this you can now run captured, non-captured lambdas, just like you are using the original:
auto capture_lambda() {
int first = 5;
auto lambda = [=](int x, int z) {
return x + z + first;
};
return lambda_expression<decltype(lambda), int, int, int>(lambda);
}
auto noncapture_lambda() {
auto lambda = [](int x, int z) {
return x + z;
};
return lambda_expression<decltype(lambda), int, int, int>(lambda);
}
void refcapture_lambda() {
int test;
auto lambda = [&](int x, int z) {
test = x + z;
};
lambda_expression<decltype(lambda), void, int, int>f(lambda);
f(2, 3);
std::cout << "test value = " << test << std::endl;
}
int main(int argc, char **argv) {
auto f_capture = capture_lambda();
auto f_noncapture = noncapture_lambda();
std::cout << "main test = " << f_capture(2, 3) << std::endl;
std::cout << "main test = " << f_noncapture(2, 3) << std::endl;
refcapture_lambda();
system("PAUSE");
return 0;
}
This code works with VS2015
Update 04.07.17:
template <typename CT, typename ... A> struct function
: public function<decltype(&CT::operator())(A...)> {};
template <typename C> struct function<C> {
private:
C mObject;
public:
function(const C & obj)
: mObject(obj) {}
template<typename... Args> typename
std::result_of<C(Args...)>::type operator()(Args... a) {
return this->mObject.operator()(a...);
}
template<typename... Args> typename
std::result_of<const C(Args...)>::type operator()(Args... a) const {
return this->mObject.operator()(a...);
}
};
namespace make {
template<typename C> auto function(const C & obj) {
return ::function<C>(obj);
}
}
int main(int argc, char ** argv) {
auto func = make::function([](int y, int x) { return x*y; });
std::cout << func(2, 4) << std::endl;
system("PAUSE");
return 0;
}
Capturing lambdas cannot be converted to function pointers, as this answer pointed out.
However, it is often quite a pain to supply a function pointer to an API that only accepts one. The most often cited method to do so is to provide a function and call a static object with it.
static Callable callable;
static bool wrapper()
{
return callable();
}
This is tedious. We take this idea further and automate the process of creating wrapper and make life much easier.
#include<type_traits>
#include<utility>
template<typename Callable>
union storage
{
storage() {}
std::decay_t<Callable> callable;
};
template<int, typename Callable, typename Ret, typename... Args>
auto fnptr_(Callable&& c, Ret (*)(Args...))
{
static bool used = false;
static storage<Callable> s;
using type = decltype(s.callable);
if(used)
s.callable.~type();
new (&s.callable) type(std::forward<Callable>(c));
used = true;
return [](Args... args) -> Ret {
return Ret(s.callable(std::forward<Args>(args)...));
};
}
template<typename Fn, int N = 0, typename Callable>
Fn* fnptr(Callable&& c)
{
return fnptr_<N>(std::forward<Callable>(c), (Fn*)nullptr);
}
And use it as
void foo(void (*fn)())
{
fn();
}
int main()
{
int i = 42;
auto fn = fnptr<void()>([i]{std::cout << i;});
foo(fn); // compiles!
}
Live
This is essentially declaring an anonymous function at each occurrence of fnptr.
Note that invocations of fnptr overwrite the previously written callable given callables of the same type. We remedy this, to a certain degree, with the int parameter N.
std::function<void()> func1, func2;
auto fn1 = fnptr<void(), 1>(func1);
auto fn2 = fnptr<void(), 2>(func2); // different function
Not a direct answer, but a slight variation to use the "functor" template pattern to hide away the specifics of the lambda type and keeps the code nice and simple.
I was not sure how you wanted to use the decide class so I had to extend the class with a function that uses it. See full example here: https://godbolt.org/z/jtByqE
The basic form of your class might look like this:
template <typename Functor>
class Decide
{
public:
Decide(Functor dec) : _dec{dec} {}
private:
Functor _dec;
};
Where you pass the type of the function in as part of the class type used like:
auto decide_fc = [](int x){ return x > 3; };
Decide<decltype(decide_fc)> greaterThanThree{decide_fc};
Again, I was not sure why you are capturing x it made more sense (to me) to have a parameter that you pass in to the lambda) so you can use like:
int result = _dec(5); // or whatever value
See the link for a complete example
A shortcut for using a lambda with as a C function pointer is this:
"auto fun = +[](){}"
Using Curl as exmample (curl debug info)
auto callback = +[](CURL* handle, curl_infotype type, char* data, size_t size, void*){ //add code here :-) };
curl_easy_setopt(curlHande, CURLOPT_VERBOSE, 1L);
curl_easy_setopt(curlHande,CURLOPT_DEBUGFUNCTION,callback);
A simular answer but i made it so you don't have to specify the type of returned pointer (note that the generic version requires C++20):
#include <iostream>
template<typename Function>
struct function_traits;
template <typename Ret, typename... Args>
struct function_traits<Ret(Args...)> {
typedef Ret(*ptr)(Args...);
};
template <typename Ret, typename... Args>
struct function_traits<Ret(*const)(Args...)> : function_traits<Ret(Args...)> {};
template <typename Cls, typename Ret, typename... Args>
struct function_traits<Ret(Cls::*)(Args...) const> : function_traits<Ret(Args...)> {};
using voidfun = void(*)();
template <typename F>
voidfun lambda_to_void_function(F lambda) {
static auto lambda_copy = lambda;
return []() {
lambda_copy();
};
}
// requires C++20
template <typename F>
auto lambda_to_pointer(F lambda) -> typename function_traits<decltype(&F::operator())>::ptr {
static auto lambda_copy = lambda;
return []<typename... Args>(Args... args) {
return lambda_copy(args...);
};
}
int main() {
int num;
void(*foo)() = lambda_to_void_function([&num]() {
num = 1234;
});
foo();
std::cout << num << std::endl; // 1234
int(*bar)(int) = lambda_to_pointer([&](int a) -> int {
num = a;
return a;
});
std::cout << bar(4321) << std::endl; // 4321
std::cout << num << std::endl; // 4321
}
Here is another variation of the solution. C++14 (can be turned into C++11) Supports return values, non-copyable and mutable lambdas. If mutable lambdas not needed, can be even shorter by removing specialization matching non-const version and embedding impl_impl.
For those who wonder, it works because each lambda is unique (is distinct class) and thus invocation of to_f generates unique for this lambda static and corresponding C-style function which can access it.
template <class L, class R, class... Args> static auto impl_impl(L l) {
static_assert(!std::is_same<L, std::function<R(Args...)>>::value,
"Only lambdas are supported, it is unsafe to use "
"std::function or other non-lambda callables");
static L lambda_s = std::move(l);
return +[](Args... args) -> R { return lambda_s(args...); };
}
template <class L>
struct to_f_impl : public to_f_impl<decltype(&L::operator())> {};
template <class ClassType, class R, class... Args>
struct to_f_impl<R (ClassType::*)(Args...) const> {
template <class L> static auto impl(L l) {
return impl_impl<L, R, Args...>(std::move(l));
}
};
template <class ClassType, class R, class... Args>
struct to_f_impl<R (ClassType::*)(Args...)> {
template <class L> static auto impl(L l) {
return impl_impl<L, R, Args...>(std::move(l));
}
};
template <class L> auto to_f(L l) { return to_f_impl<L>::impl(std::move(l)); }
Note, this also tend to work for other callable objects like std::function but it would be better if it didn't work because unlike lambdas, std::function like objects do not generate unique type so inner template and its inner static will be reused for/shared by all functions with same signature, which most probably is not what we want from it. I've specifically disallowed std::function but there exist more which I don't know how to disallow in generic way.
While the template approach is clever for various reasons, it is important to remember the lifecycle of the lambda and the captured variables. If any form of a lambda pointer is is going to be used and the lambda is not a downward continuation, then only a copying [=] lambda should used. I.e., even then, capturing a pointer to a variable on the stack is UNSAFE if the lifetime of those captured pointers (stack unwind) is shorter than the lifetime of the lambda.
A simpler solution for capturing a lambda as a pointer is:
auto pLamdba = new std::function<...fn-sig...>([=](...fn-sig...){...});
e.g., new std::function<void()>([=]() -> void {...}
Just remember to later delete pLamdba so ensure that you don't leak the lambda memory.
Secret to realize here is that lambdas can capture lambdas (ask yourself how that works) and also that in order for std::function to work generically the lambda implementation needs to contain sufficient internal information to provide access to the size of the lambda (and captured) data (which is why the delete should work [running destructors of captured types]).
As it was mentioned by the others you can substitute Lambda function instead of function pointer. I am using this method in my C++ interface to F77 ODE solver RKSUITE.
//C interface to Fortran subroutine UT
extern "C" void UT(void(*)(double*,double*,double*),double*,double*,double*,
double*,double*,double*,int*);
// C++ wrapper which calls extern "C" void UT routine
static void rk_ut(void(*)(double*,double*,double*),double*,double*,double*,
double*,double*,double*,int*);
// Call of rk_ut with lambda passed instead of function pointer to derivative
// routine
mathlib::RungeKuttaSolver::rk_ut([](double* T,double* Y,double* YP)->void{YP[0]=Y[1]; YP[1]= -Y[0];}, TWANT,T,Y,YP,YMAX,WORK,UFLAG);

How to achieve dynamic polymorphism (run-time call dispatch) on unrelated types?

GOAL:
I would like to achieve type-safe dynamic polymorphism (i.e. run-time dispatch of a function call) on unrelated types - i.e. on types which do not have a common base class. It seems to me that this is achievable, or at least theoretically sound. I will try to define my problem more formally.
PROBLEM DEFINITION:
Given the following:
two or more unrelated types A1, ..., An, each of which has a method called f, possibly with different signatures, but with the same return type R; and
a boost::variant<A1*, ..., An*> object v (or whatever other type of variant) which can and must assume at any time one value of any of those types;
My goal is to write instructions conceptually equivalent to v.f(arg_1, ..., arg_m); that would get dispatched at run-time to function Ai::f if the actual type of the value contained in v is Ai. If the call arguments are not compatible with the formal parameters of each function Ai, the compiler should raise an error.
Of course I do not need to stick to the syntax v.f(arg_1, ..., arg_m): for instance, something like call(v, f, ...) is also acceptable.
I tried to achieve this in C++, but so far I have failed to come up with a good solution (I do have a bunch of bad ones). Below I clarify what I mean by "good solution".
CONSTRAINTS:
A good solution is anything that lets me mimic the v.f(...) idiom, e.g. call_on_variant(v, f, ...);, and satisfies the following constraints:
does not require any sort of separate declaration for each function f that must be called this way (e.g. ENABLE_CALL_ON_VARIANT(f)) or for any list of unrelated types A1, ..., An that can be treated polymorphically (e.g. ENABLE_VARIANT_CALL(A1, ..., An)) somewhere else in the code, especially on global scope;
does not require to explicitly name the types of the input arguments when doing the call (e.g. call_on_variant<int, double, string>(v, f, ...)). Naming the return type is OK, so for instance call_on_variant<void>(v, f, ...) is acceptable.
Follows a demonstrative example that hopefully clarifies my wish and requirements.
EXAMPLE:
struct A1 { void f(int, double, string) { cout << "A"; } };
struct A2 { void f(int, double, string) { cout << "B"; } };
struct A3 { void f(int, double, string) { cout << "C"; } };
using V = boost::variant<A1, A2, A3>;
// Do not want anything like the following here:
// ENABLE_VARIANT_CALL(foo, <whatever>)
int main()
{
A a;
B b;
C c;
V v = &a;
call_on_variant(v, f, 42, 3.14, "hello");
// Do not want anything like the following here:
// call_on_variant<int, double, string>(v, f, 42, 3.14, "hello");
V v = &b;
call_on_variant(v, f, 42, 3.14, "hello");
V v = &c;
call_on_variant(v, f, 42, 3.14, "hello");
}
The output of this program should be: ABC.
BEST (FAILED) ATTEMPT:
The closest I got to the desired solution is this macro:
#define call_on_variant(R, v, f, ...) \
[&] () -> R { \
struct caller : public boost::static_visitor<void> \
{ \
template<typename T> \
R operator () (T* pObj) \
{ \
pObj->f(__VA_ARGS__); \
} \
}; \
caller c; \
return v.apply_visitor(c); \
}();
Which would work perfectly, if only template members were allowed in local classes (see this question). Does anybody have an idea how to fix this, or suggest an alternative approach?
Some time has passed, C++14 is being finalized, and compilers are adding support for new features, like generic lambdas.
Generic lambdas, together with the machinery shown below, allow achieving the desired (dynamic) polymorphism with unrelated classes:
#include <boost/variant.hpp>
template<typename R, typename F>
class delegating_visitor : public boost::static_visitor<R>
{
public:
delegating_visitor(F&& f) : _f(std::forward<F>(f)) { }
template<typename T>
R operator () (T x) { return _f(x); }
private:
F _f;
};
template<typename R, typename F>
auto make_visitor(F&& f)
{
using visitor_type = delegating_visitor<R, std::remove_reference_t<F>>;
return visitor_type(std::forward<F>(f));
}
template<typename R, typename V, typename F>
auto vcall(V&& vt, F&& f)
{
auto v = make_visitor<R>(std::forward<F>(f));
return vt.apply_visitor(v);
}
#define call_on_variant(val, fxn_expr) \
vcall<int>(val, [] (auto x) { return x-> fxn_expr; });
Let's put this into practice. Supposing to have the following two unrelated classes:
#include <iostream>
#include <string>
struct A
{
int foo(int i, double d, std::string s) const
{
std::cout << "A::foo(" << i << ", " << d << ", " << s << ")";
return 1;
}
};
struct B
{
int foo(int i, double d, std::string s) const
{
std::cout << "B::foo(" << i << ", " << d << ", " << s << ")";
return 2;
}
};
It is possible to invoke foo() polymorphically this way:
int main()
{
A a;
B b;
boost::variant<A*, B*> v = &a;
auto res1 = call_on_variant(v, foo(42, 3.14, "Hello"));
std::cout << std::endl<< res1 << std::endl;
v = &b;
auto res2 = call_on_variant(v, foo(1337, 6.28, "World"));
std::cout << std::endl<< res2 << std::endl;
}
And the output is, as expected:
A::foo(42, 3.14, Hello)
1
B::foo(1337, 6.28, World)
2
The program has been tested on VC12 with November 2013's CTP. Unfortunately, I do not know of any online compiler that supports generic lambdas, so I cannot post a live example.
OK, here's a wild shot:
template <typename R, typename ...Args>
struct visitor : boost::static_visitor<R>
{
template <typename T>
R operator()(T & x)
{
return tuple_unpack(x, t); // this needs a bit of code
}
visitor(Args const &... args) : t(args...) { }
private:
std::tuple<Args...> t;
};
template <typename R, typename Var, typename ...Args>
R call_on_variant(Var & var, Args const &... args)
{
return boost::apply_visitor(visitor<R, Args...>(args...), var);
}
Usage:
R result = call_on_variant<R>(my_var, 12, "Hello", true);
I've hidden a certain amount of work you need for calling a function by unpacking a tuple, but I believe this has been done elsewhere on SO.
Also, if you need to store references rather than copies of the arguments, this can possibly be done, but needs more care. (You can have a tuple of references. But you have to think about whether you also want to allow temporary objects.)
Unfortunately, this cannot be done in C++ (yet - see the conclusions). Follows a proof.
CONSIDERATION 1: [on the need of templates]
In order to determine the correct member function Ai::f to be invoked at run-time when the expression call_on_variant(v, f, ...) is met (or any equivalent form of it), it is necessary, given the variant object v, to retrieve the type Ai of the value being held by v. Doing so necessarily requires the definition of at least one (class or function) template.
The reason for this is that no matter how this is done, what is needed is to iterate over all the types the variant can hold (the type list is exposed as boost::variant<...>::types, check whether the variant is holding a value of that type (through boost::get<>), and (if so) retrieve that value as the pointer through which the member function invocation must be performed (internally, this is also what boost::apply_visitor<> does).
For each single type in the list, this can be done this way:
using types = boost::variant<A1*, ..., An*>::types;
mpl::at_c<types, I>::type* ppObj = (get<mpl::at_c<types, I>::type>(&var));
if (ppObj != NULL)
{
(*ppObj)->f(...);
}
Where I is a compile-time constant. Unfortunately, C++ does not allow for a static for idiom that would allow a sequence of such snippets to be generated by the compiler based on a compile-time for loop. Instead, template meta-programming techniques must be used, such as:
mpl::for_each<types>(F());
where F is a functor with a template call operator. Directly or indirectly, at least one class or function template needs to be defined, since the lack of static for forces the programmer to code the routine that must be repeated for each type generically.
CONSIDERATION 2: [on the need of locality]
One of the constraints for the desired solution (requirement 1 of the section "CONSTRAINTS" in the question's text) is that it shall not be necessary to add global declarations or any other declaration at any other scope than the one where the function call is being done. Therefore, no matter whether macro expansion or template meta-programming is involved, what needs to be done must be done in the place where the function call occurs.
This is problematic, because "CONSIDERATION 1" above has proved that it is needed to define at least one template to carry out the task. The problem is that C++ does not allow templates to be defined at local scope. This is true of class templates and function templates, and there is no way to overcome this restriction. Per §14/2:
"A template-declaration can appear only as a namespace scope or class scope declaration"
Thus, the generic routines we have to define in order to do the job must be defined elsewhere than at call site, and must be instantiated at call-site with proper arguments.
CONSIDERATION 3: [on function names]
Since the call_on_variant() macro (or any equivalent construct) must be able to handle any possible function f, the name of f must be passed in as an argument to our template-based, type resolving machinery. It is important to stress that only the name of the function shall be passed, because the particular function Ai::f that needs to be invoked must be determined by the template machinery.
However, names cannot be template arguments, because they do not belong to the type system.
CONCLUSION:
The combination of the three considerations above proves that this problem cannot be solved in C++ as of today. It requires either the possibility of using names as template arguments or the possibility of defining local templates. While the first thing is undesirable at least, the second one might make sense, but it is not being taken into consideration by the standardization committee. However, one exception is likely to be admitted.
FUTURE OPPORTUNITIES:
Generic lambdas, which are being strongly pushed to get into the next C++ standard, are in fact local classes with a template call operator.
Thus, even though the macro I posted at the end of the question's text will still not work, an alternative approach seems viable (with some tweaking required for handling return types):
// Helper template for type resolution
template<typename F, typename V>
struct extractor
{
extractor(F f, V& v) : _f(f), _v(v) { }
template<typename T>
void operator () (T pObj)
{
T* ppObj = get<T>(&_v));
if (ppObj != NULL)
{
_f(*ppObj);
return;
}
}
F _f;
V& _v;
};
// v is an object of type boost::variant<A1*, ..., An*>;
// f is the name of the function to be invoked;
// The remaining arguments are the call arguments.
#define call_on_variant(v, f, ...) \
using types = decltype(v)::types; \
auto lam = [&] (auto pObj) \
{ \
(*pObj)->f(__VA_ARGS__); \
}; \
extractor<decltype(lam), decltype(v)>(); \
mpl::for_each<types>(ex);
FINAL REMARKS:
This is an interesting case of type-safe call that is (sadly) not supported by C++. This paper by Mat Marcus, Jaakko Jarvi, and Sean Parent seems to show that dynamic polymorphism on unrelated types is crucial to achieve an important (in my opinion, fundamental and unavoidable) paradigm shift in programming.
I once solved this by simulating .NET delegates:
template<typename T>
class Delegate
{
//static_assert(false, "T must be a function type");
};
template<typename ReturnType>
class Delegate<ReturnType()>
{
private:
class HelperBase
{
public:
HelperBase()
{
}
virtual ~HelperBase()
{
}
virtual ReturnType operator()() const = 0;
virtual bool operator==(const HelperBase& hb) const = 0;
virtual HelperBase* Clone() const = 0;
};
template<typename Class>
class Helper : public HelperBase
{
private:
Class* m_pObject;
ReturnType(Class::*m_pMethod)();
public:
Helper(Class* pObject, ReturnType(Class::*pMethod)()) : m_pObject(pObject), m_pMethod(pMethod)
{
}
virtual ~Helper()
{
}
virtual ReturnType operator()() const
{
return (m_pObject->*m_pMethod)();
}
virtual bool operator==(const HelperBase& hb) const
{
const Helper& h = static_cast<const Helper&>(hb);
return m_pObject == h.m_pObject && m_pMethod == h.m_pMethod;
}
virtual HelperBase* Clone() const
{
return new Helper(*this);
}
};
HelperBase* m_pHelperBase;
public:
template<typename Class>
Delegate(Class* pObject, ReturnType(Class::*pMethod)())
{
m_pHelperBase = new Helper<Class>(pObject, pMethod);
}
Delegate(const Delegate& d)
{
m_pHelperBase = d.m_pHelperBase->Clone();
}
Delegate(Delegate&& d)
{
m_pHelperBase = d.m_pHelperBase;
d.m_pHelperBase = nullptr;
}
~Delegate()
{
delete m_pHelperBase;
}
Delegate& operator=(const Delegate& d)
{
if (this != &d)
{
delete m_pHelperBase;
m_pHelperBase = d.m_pHelperBase->Clone();
}
return *this;
}
Delegate& operator=(Delegate&& d)
{
if (this != &d)
{
delete m_pHelperBase;
m_pHelperBase = d.m_pHelperBase;
d.m_pHelperBase = nullptr;
}
return *this;
}
ReturnType operator()() const
{
(*m_pHelperBase)();
}
bool operator==(const Delegate& d) const
{
return *m_pHelperBase == *d.m_pHelperBase;
}
bool operator!=(const Delegate& d) const
{
return !(*this == d);
}
};
You can use it much like .NET delegates:
class A
{
public:
void M() { ... }
};
class B
{
public:
void M() { ... }
};
A a;
B b;
Delegate<void()> d = Delegate<void()>(&a, &A::M);
d(); // calls A::M
d = Delegate<void()>(&b, &B::M);
d(); // calls B::M
This works with methods that have no arguments. If you can use C++11, you can modify it to use variadic templates to handle any number of parameters. Without C++11, you need to add more Delegate specializations to handle specific numbers of parameters:
template<typename ReturnType, typename Arg1>
class Delegate<ReturnType(Arg1)>
{
...
};
template<typename ReturnType, typename Arg1, typename Arg2>
class Delegate<ReturnType(Arg1, Arg2)>
{
...
};
With this Delegate class you can also emulate .NET events, which are based on delegates.