C++: Template binding object and method using lambda expression - c++

Due to the fact that std::functional uses heap memory when combining it with an std::bind I wanted to replace the std::bind with a lambda expression but I do not quite know how to do this. Is this even possible?
#include <iostream>
#include <functional>
#include <utility>
template<typename Signature>
class Callback;
template<typename R, typename... Args>
class Callback<R(Args...)> final
{
public:
Callback() noexcept : mFunc() {}
template<typename Obj, typename Method,
typename std::enable_if_t<std::is_invocable_r<R, Method, Obj, Args...>::value, int> = 0>
Callback(Obj& obj, Method method)
{
// That does not work
mFunc = [&obj](Args... args){ return obj.method(args); };
// mFunc = std::bind(method, obj, std::placeholders::_1, std::placeholders::_1); would work
}
R operator()(Args... args) const { return mFunc(args...); }
private:
std::function<R(Args...)> mFunc;
};
struct Foo
{
Foo() {}
void print(int a, int b)
{
std::cout << a << b << "\n";
}
};
int main()
{
Foo foo;
Callback<void(int, int)> cb(foo, &Foo::print);
cb(1,2);
}
Compiler throws the following error message:
main.cpp:19:46: error: expression contains unexpanded parameter pack 'args'
mFunc = [&obj](Args... args){ return obj.method(args); };
^ ~~~~
main.cpp:19:19: warning: lambda capture 'obj' is not used [-Wunused-lambda-capture]
mFunc = [&obj](Args... args){ return obj.method(args); };

If you really want to pass a member function pointer then you need to use syntax for calling the method via a member function pointer:
mFunc = [&,method](Args...x){ return (obj.*method)(x...);};
However, it would be simpler if you'd accept free callables and let the caller bind the object to a member function if necessary.

Related

Forwarding tuple<...> containing deleted copy constructor

I have a function wrapper for use over the network:
#pragma once
#include <tuple>
#include <functional>
struct ZPackage {
std::unique_ptr<int> m_dummy;
template<typename T>
T Read() {
T t = T();
return t;
}
};
class ZRpc;
template <class C, class Tuple, class F, size_t... Is>
constexpr auto invoke_tuple_impl(F f, C& c, ZRpc* rpc, Tuple t, std::index_sequence<Is...>) {
return std::invoke(f, c, rpc, std::move(std::get<Is>(t))...);
}
template <class C, class Tuple, class F>
constexpr void invoke_tuple(F f, C& c, ZRpc* rpc, Tuple t) {
invoke_tuple_impl(f, c, rpc, std::move(t),
std::make_index_sequence < std::tuple_size<Tuple>{} > {}); // last arg is for template only
}
class ZRpcMethodBase
{
public:
virtual void Invoke(ZRpc* pao, ZPackage& pkg) = 0;
};
template<class C, class...Args>
class ZRpcMethod final : public ZRpcMethodBase {
using Lambda = void(C::*)(ZRpc*, Args...);
C* object;
Lambda lambda;
template<class F>
auto Invoke_impl(ZPackage& pkg) {
return std::tuple(pkg.Read<F>());
}
// Split a param,
// Add that param from Packet into tuple
template<class F, class S, class...R>
auto Invoke_impl(ZPackage& pkg) {
auto a(Invoke_impl(pkg));
std::tuple<S, R...> b = Invoke_impl<S, R...>(pkg);
return std::tuple_cat(a, b);
}
public:
ZRpcMethod(C* object, Lambda lam) : object(object), lambda(lam) {}
void Invoke(ZRpc* rpc, ZPackage& pkg) override {
// Invoke_impl returns a tuple of types by recursion
if constexpr (sizeof...(Args))
{
auto tupl = Invoke_impl<Args...>(pkg);
invoke_tuple(lambda, object, rpc, tupl);
}
else
{
// works like ~magic~
std::invoke(lambda, object, rpc);
}
}
};
I have added in some of the types that are utilized, ZRpc, ZPackage, and an example Object.
I am struggling with getting this wrapper to work with types that have a deleted copy constructor, such as std::unique_ptr (or in this example the ZPackage which contains the std::unique_ptr. The specific error I get:
std::tuple::tuple(const std::tuple &)': attempting to reference a deleted function
#include "TestRpc.h"
class ZRpc { };
struct Object {
void ok_method(ZRpc* rpc, int i) {
}
void broken_method(ZRpc* rpc, ZPackage pkg) {
}
};
int main() {
ZRpc rpc;
Object obj;
// compiles fine
auto a = new ZRpcMethod(&obj, &Object::ok_method);
// does not compile
auto b = new ZRpcMethod(&obj, &Object::broken_method);
}
I doubt that it will make a difference, but just for reference, here are some things I have tried and commented out previously with no avail: https://pastebin.com/aHSsLzWe. I am unable to wrap my head around variadic templates and how to correctly forward.
How can I achieve perfect forwarding with move-only constructor types?
EDIT:
I changed the std::forward to move
In the Invoke() function body, since if constexpr (sizeof...(Args)) == 1 is true, this will invoke Invoke_impl<Args...>(pkg) which will return a std::tuple<ZPackage> which is move-only, so you also need to std::move it into invoke_tuple().
if constexpr (sizeof...(Args)) {
auto tupl = Invoke_impl<Args...>(pkg);
invoke_tuple(lambda, object, rpc, std::move(tupl));
} else {
// ...
}

Passing member function to Template function

Given the following function:
template<class F, class... Args>
auto ThreadPool::enqueue(F&& f, Args&&... args)
-> std::future<typename std::result_of<F(Args...)>::type>
{
using return_type = typename std::result_of<F(Args...)>::type;
auto task = std::make_shared< std::packaged_task<return_type()> >(
std::bind(std::forward<F>(f), std::forward<Args>(args)...)
);
std::future<return_type> res = task->get_future();
return res;
}
What's the right way to pass a member function to ThreadPool::enqueue as parameter, say the object is:
Foo foo
and the function is:
foo.do_something();
I have tried to use std::bind and std::mem_fn with or without "&" and all failed.
In addition to what #IgorTandetnik has mentioned in the comments, you can also use std::bind with std::mem_fn to pass a member function to your method:
struct Foo
{
void do_something() {}
void do_something_else(int x, int y, std::string str) {}
};
int main()
{
Foo foo;
ThreadPool pool;
auto func_sth = std::bind(std::mem_fn(&Foo::do_something), foo);
auto func_sth_else = std::bind(std::mem_fn(&Foo::do_something_else), foo, 10 , 11, "hi");
pool.enqueue(func_sth);
pool.enqueue(func_sth_else);
return 0;
}

Creating a template to wrap C++ member functions and expose as C callbacks

When a C++ application uses a C library that has callbacks in the API, a common pattern is for the app to define static functions that translate some void* user data argument into a class pointer and then call the appropriate member function. The duplication wastes time both writing and reading. It would be nice to have a template function to do this wrapping for me.
I've got part of the way there already...
// C library with some callbacks
typedef void (*CallbackTypeOne)(void* userdata, double arg1);
typedef void (*CallbackTypeTwo)(void* userdata, int arg1);
typedef void (*CallbackTypeThree)(void* userdata, int arg1, float arg2);
typedef void(*GenericCallback)();
void registerAndCallCallback(int typeID, GenericCallback callback, void* userdata)
{
switch (typeID) {
case 0: ((CallbackTypeOne)callback)(userdata, 42.0); break;
case 1: ((CallbackTypeTwo)callback)(userdata, 42); break;
case 2: ((CallbackTypeThree)callback)(userdata, 42, 42.0f); break;
};
}
// C++ app using the above library
class MyClass
{
public:
MyClass()
{
// Ideal short syntax, but doesn't compile
registerAndCallCallback(0,
reinterpret_cast<GenericCallback>(
&staticCallback<MyClass::callbakcOne>),
this);
// main.cpp:26:36: error: reinterpret_cast cannot resolve overloaded function 'staticCallback' to type 'GenericCallback' (aka 'void (*)()')
// A bit more explicit but without providing 'Args' to staticCallback
registerAndCallCallback(0,
reinterpret_cast<GenericCallback>(
&staticCallback<decltype(&MyClass::callbakcOne),
&MyClass::callbakcOne>),
this);
// main.cpp:52:36: error: too few arguments to function call, expected 1, have 0
// (instance->*cb)(args...);
// ~~~~~~~~~~~~~ ^
// main.cpp:37:22: note: in instantiation of function template specialization 'MyClass::staticCallback<void (MyClass::*)(double), &MyClass::callbakcOne>' requested here
// &staticCallback<decltype(&MyClass::callbakcOne),
// ^
// This works, but I feel there should be a nicer way that avoids having to pass the callback arguments. Avoiding the duplication in decltype would be nice too.
registerAndCallCallback(0,
reinterpret_cast<GenericCallback>(
&staticCallback<decltype(&MyClass::callbakcOne),
&MyClass::callbakcOne, double>),
this);
registerAndCallCallback(1, reinterpret_cast<GenericCallback>(&staticCallback<decltype(&MyClass::callbakcTwo), &MyClass::callbakcTwo, int>), this);
registerAndCallCallback(2, reinterpret_cast<GenericCallback>(&staticCallback<decltype(&MyClass::callbakcThree), &MyClass::callbakcThree, int, float>), this);
}
void callbakcOne(double arg1) {}
void callbakcTwo(int arg1) {}
void callbakcThree(int arg1, float arg2) {}
template<typename MemberCB, MemberCB cb, typename... Args>
static void staticCallback(void* userdata, Args... args)
{
auto instance = reinterpret_cast<MyClass*>(userdata);
(instance->*cb)(args...);
}
};
int main()
{
MyClass myclass;
return 0;
}
How can I write the template function staticCallback so that I can just give it a member function to wrap and it can take care of the argument types etc for me?
This question is quite similar and kudos to #fredbaba for the inspiration to solve this.
Anyway, to achieve this, you can use a singleton function factory pattern to get static instances of bindable function objects. The basic approach is to bind your class member function to a static function wrapper that has an invoke method taking the arguments the c library expects, forwarding and casting as necessary.
Tested with gcc 8.3 with -std=c++14
Demonstration:
template <typename TypeID, typename T, typename RetType, typename... Args>
struct FunctionFactory
{
public:
static void bind(RetType(T::*f)(Args...)) {
instance().fn_ = [f](T* t, Args... args) {
return (t->*f)(std::forward<Args>(args)...);
};
}
static RetType invoke(void* userdata, Args... args) {
T * t = reinterpret_cast<T*>(userdata);
return instance().fn_(t, std::forward<Args>(args)...);
}
typedef decltype(&FunctionFactory::invoke) pointer_type;
static pointer_type ptr() {
return &invoke;
}
private:
static FunctionFactory & instance() {
static FunctionFactory inst_;
return inst_;
}
FunctionFactory() = default;
std::function<RetType(T*, Args...)> fn_;
};
template <typename TypeID, typename T, typename RetType, typename... Args>
typename FunctionFactory<TypeID, T, RetType, Args...>::pointer_type
getFunctionPtr(RetType(T::*f)(Args...))
{
FunctionFactory<TypeID, T, RetType, Args...>::bind(f);
return FunctionFactory<TypeID, T, RetType, Args...>::ptr();
}
class MyClass
{
public:
MyClass()
{
registerAndCallCallback(0, reinterpret_cast<GenericCallback>(getFunctionPtr<0>(&MyClass::callbackOne)), this);
registerAndCallCallback(1, reinterpret_cast<GenericCallback>(getFunctionPtr<1>(&MyClass::callbackTwo)), this);
registerAndCallCallback(2, reinterpret_cast<GenericCallback>(getFunctionPtr<2>(&MyClass::callbackThree)), this);
}
void callbackOne(double arg1) {}
void callbackTwo(int arg1) {}
void callbackThree(int arg1, float arg2) {}
};

Passing member function pointer as template parameter

I want to create a wrapper class which is able to call member functions (of any type) of the wrapped class with help of templates. This is what I have so far:
template <typename T>
class wrapper {
public:
template<typename R, R (T::*func)()>
void call_func() {
(wrapped.*func)();
}
private:
T wrapped;
};
class some_class {
private:
int i = 2;
public:
void some_func() {
std::cout << i << std::endl;
}
};
int main() {
wrapper<some_class> wr;
// How I need to call at the moment:
wr.call_func<void, &some_class::some_func>();
// How I want call:
wr.call_func<&some_class::some_func>();
return 0;
}
As you can see in the comments of the main function, I want to call the wrapper-function without explicitly specifying the return type of the wrapped member function. (How) Can this be done in C++11?
template<typename F>
void call_func(F func) {
(wrapped.*func)();
}
then call like this:
wr.call_func(&some_class::some_func);
If you want to use the return value too, you'll need this:
template<typename F>
auto call_func(F func) -> decltype((std::declval<T>().*func)()) {
return (wrapped.*func)();
}
If you have C++14, you can omit the -> decltype(...) part and use decltype(auto) as the return value.
If you also want to pass functions, you can use variadic templates and forwarding for that.
template<typename F, typename... Args>
decltype(auto) call_func(F func, Args&&... args) {
return (wrapped.*func)(std::forward<Args>(args)...);
}
You can directly use std::function
For more information on std::function see: http://en.cppreference.com/w/cpp/utility/functional/function

Constructor overloads to accept any function

I am attempting to create a class template whose constructor(s) can take any kind of function as argument, that is, it takes a function pointer (which can be a member function pointer) and the corresponding function arguments. Additionally, there should be a static_assert that checks whether the function return type (taken from the function pointer) matches the class template parameter type. Thus, the code should look something like this:
template <class ReturnType>
struct Bar
{
template <class RetType, class ... ParamType>
Bar<ReturnType>(RetType (* func)(ParamType ...), ParamType && ... args) :
package_(std::bind(func, std::forward<ParamType>(args) ...)),
function_([this] { package_(); }),
future_(package_.get_future())
{
static_assert(std::is_same<ReturnType, RetType>::value,
"Type mismatch between class parameter type and constructor parameter type");
}
template <class RetType, class ObjType, class ... ParamType>
Bar<ReturnType>(RetType (ObjType::* func)(ParamType ...), ObjType * obj, ParamType && ... args) :
package_(std::bind(func, obj, std::forward<ParamType>(args) ...)),
function_([this] { package_(); }),
future_(package_.get_future())
{
static_assert(std::is_same<ReturnType, RetType>::value,
"Type mismatch between class parameter type and constructor parameter type");
}
std::packaged_task<ReturnType()> package_;
std::function<void()> function_;
std::future<ReturnType> future_;
};
The idea is that the code compiles for these situations, and allows for Bar::function_ to be called (through the function call operator) without errors:
struct Foo
{
int foo(int i) {
return i;
}
int foo() {
return 1;
}
};
int foo(int i)
{
return i;
}
int foo()
{
return 1;
}
int main()
{
Foo f = Foo();
Bar<int> b1(&Foo::foo, &f, 1);
Bar<int> b2(&Foo::foo, &f);
Bar<int> b3(foo, 1);
Bar<int> b4(foo);
return 0;
}
Unfortunately, I have close to zero experience with template metaprogramming, and even though I have ran over several questions here in SO, and attempted several ways of solving my problem, such as using a more generalized approach to the constructor
template <class RetType, class ... ParamType>
Bar<ReturnType>(RetType func, ParamType && ... args)
and combining it with type_traits to determine the return type), I have yet to find a way to make this work. What changes can I do to the constructor(s) that allow this functionality?
Edit:
max66's answer solved my original problem, however, a new one arose, which I hadn't considered in the previous question. I also want to be able to pass variables to the constructor, like so:
int main()
{
Foo f = Foo();
int i = 1;
Bar<int> b1(&Foo::foo, &f, i); // Error
Bar<int> b2(&Foo::foo, &f, 1); // Ok
Bar<int> b3(&Foo::foo, &f); // Ok
Bar<int> b4(foo, i); // Error
Bar<int> b5(foo, 1); // Ok
Bar<int> b6(foo); // Ok
return 0;
}
however, as it is, a compiler error shows up in the cases marked with Error. I am guessing this is because the parameter func in the constructor uses ParamType to determine its type (which doesn't match with the actual ParamTypes in the case of b1 and b4), but I have no idea how to solve this...
You probably want to use std::invoke. It handles working with member function pointers and regular functions for you.
As an outline of the sort of stuff you can do:
#include <functional>
#include <type_traits>
#include <utility>
template<typename F>
class Bar
{
F f_;
public:
template<typename TF>
Bar(TF && f)
: f_{ std::forward<TF>(f) }
{}
template<typename... Args>
decltype(auto) operator()(Args &&... args) {
return std::invoke(f_, std::forward<Args>(args)...);
}
};
template<typename F>
auto make_bar(F && f)
{
return Bar<std::decay_t<F>>{ std::forward<F>(f) };
}
It can be used like so:
auto b1 = make_bar(&f);
auto result = b1(myArg1, myArg2); // etc
auto b2 = make_bar(&Foo::fn);
auto result = b1(foo, arg1);
In the very least, I would recommend having Bar take the function object type as a template parameter so that you don't have to use std::function, but if you do want to use the exact calling syntax you have, it can be done using std::invoke and std::invoke_result as well.
Sorry but... if you want that the return type of the funtion is equal to the template parameter of the class... why don't you simply impose it?
I mean... you can use ReturnType instead of RetType, as follows
template <typename ReturnType>
struct Bar
{
template <typename ... ParamType>
Bar<ReturnType> (ReturnType (*func)(ParamType ...), ParamType && ... args)
: package_(std::bind(func, std::forward<ParamType>(args) ...)),
function_([this] { package_(); }),
future_(package_.get_future())
{ }
template <typename ObjType, typename ... ParamType>
Bar<ReturnType> (ReturnType (ObjType::* func)(ParamType ...),
ObjType * obj, ParamType && ... args)
: package_(std::bind(func, obj, std::forward<ParamType>(args) ...)),
function_([this] { package_(); }),
future_(package_.get_future())
{ }
-- EDIT --
To solve the second problem, IF your not interested in moving parameters, you can throw away std::forward and &&, and simply write
template <typename ReturnType>
struct Bar
{
template <typename ... ParamType>
Bar<ReturnType> (ReturnType (*func)(ParamType ...),
ParamType const & ... args)
: package_(std::bind(func, args...)),
function_([this] { package_(); }),
future_(package_.get_future())
{ }
template <typename ObjType, typename ... ParamType>
Bar<ReturnType> (ReturnType (ObjType::* func)(ParamType ...),
ObjType * obj, ParamType const & ... args)
: package_(std::bind(func, obj, args...)),
function_([this] { package_(); }),
future_(package_.get_future())
{ }