C++ 11 bound std::function vs storing tuple and unpacking - c++

First off, I am still relatively new to C++11, so if I am missing anything, pardon my oversight. So what I am trying to do is basically have caller pass in a function and arbitrary # of arguments for that function, store that off and then call it asynchronously later on. And it seems there are 2 main options for this:
use std::bind to bind a std::function to its arguments (which is obtained using variadic template) and then invoke it later
convert the parameter pack into a tuple, store that and std::function, then unpack tuple into multiple args again and invoke function using that
Question is, is one way better than the other? Are there pro/cons/performance benefits of one over the other?
Thanks!
EDIT: as requested, here is a clarification, the first case is more early binding where I bind args to function as soon as caller passes them on and I store the bound func to be called later. the 2nd case is where I store func and args separately and invoke function with the args later on when it has to be called. So question is which is better performance/codesize/style/etc?

Accept a std::function<...> with the appropriate signature, store it to callback later. Let the caller decide how they prefer to create/populate the parameter. E.g.,
#include <functional>
#include <iostream>
std::function<int(int)> stored_f;
void set_callback(std::function<int(int)> f) {
stored_f = std::move(f);
}
void run_the_callback(int value) {
std::cout << stored_f(value) << '\n';
}
int f(int i) {
return i + 1;
}
int g(int a, int b) {
return a + b;
}
int main() {
// Plain old function pointer
set_callback(f);
run_the_callback(1);
// Use std::bind
set_callback(std::bind(g, 2, std::placeholders::_1));
run_the_callback(2);
// Use a lambda
set_callback([](int i){ return f(i) * g(i, i);});
run_the_callback(3);
}
Best performance - if you don't absolutely require type erasure of the callback - would be to parameterize your code on functor type. E.g.:
#include <functional>
#include <iostream>
template <typename Functor>
void do_stuff_and_callback_sometimes(Functor f) {
std::cout << f(1) << '\n';
// do some stuff, then
std::cout << f(2) << '\n';
// more work, and finally
std::cout << f(3) << "\n\n";
}
int f(int i) {
return i + 1;
}
int g(int a, int b) {
return a + b;
}
int main() {
// Plain old function pointer
do_stuff_and_callback_sometimes(f);
// Use std::bind
do_stuff_and_callback_sometimes(std::bind(g, 2, std::placeholders::_1));
// Use a lambda
do_stuff_and_callback_sometimes([](int i){ return f(i) * g(i, i);});
}
Avoiding type erasure is impossible in some situations, and in others will require you to jump through hoops. Whether or not it's worthwhile to do so is situational.

A third possibility is to move the responsibility of binding all the parameters to the caller, and only keep a std::function with the signature you intend to call.
For example:
struct Silly
{
using Callback = std::function<void()>;
void registerCallback(Callback cb) { callback_ = std::move(cb); }
Callback callback_;
};
This way it is quite obvious that it is the caller's responsibility to deal with lifetime, value vs. reference semantics for the arguments, etc.

Related

What is the most efficient way to pass a non generic function?

I am learning functional programming in C++. My intention is to pass a non generic function as argument. I know about the template method, however I would like to restrict the function signature as part of the API design. I worked out 4 different methods example on cpp.sh:
// Example program
#include <iostream>
#include <string>
#include <functional>
typedef int(functor_type)(int);
int by_forwarding(functor_type &&x) {
return x(1);
}
int functor_by_value(functor_type x) {
return x(1);
}
int std_func_by_value(std::function<functor_type> x) {
return x(1);
}
int std_func_by_forwarding(std::function<functor_type> &&x) {
return x(1);
}
int main()
{
std::cout << functor_by_value([](int a){return a;}); // works
std::cout << std_func_by_value([](int a){return a;}); // works
std::cout << std_func_by_forwarding(std::move([](int a){return a;})); // works
//std::cout << by_forwarding([](int a){return a;}); // how to move lambda with forwarding ?
}
Is any of the above attempts correct? If not, how do i achieve my goal?
(based on clarification from comments)
Signature can be restricted by using std::is_invocable:
template<typename x_Action> auto
functor_by_value(x_Action && action)
{
static_assert(std::is_invocable_r_v<int, x_Action, int>);
return action(1);
}
online compiler
Other alternative:
template <typename Func>
auto functor_by_value(Func&& f)
-> decltype(std::forward<Func>(f)(1))
{
return std::forward<Func>(f)(1);
}
however I would like to restrict the function signature as part of the API design.
So restrict it:
#include <functional>
#include <type_traits>
#include <iostream>
/// #tparam F is a type which is callable, accepting an int and returning an int
template
<
class F,
std::enable_if_t
<
std::is_convertible_v<F, std::function<int(int)>>
>* = nullptr
>
int myfunc(F &&x) {
return x(1);
}
int main()
{
auto a = myfunc([](int x) { std::cout << x << std::endl; return 1; });
// does not compile
// auto b = myfunc([]() { std::cout << "foo" << std::endl; return 1; });
}
As usual, this depends on how good your compiler is today, and how good it will be in the future.
Currently, compilers are not very good at optimizing std::function. Surprisingly, std::function is a complicated object that sometimes has to allocate memory to maintain stateful lambda functions. It also complicates matters that std::function has to be able to refer to member function, regular functions, and lambdas, and do it in a transparent manner. This transparency has a hefty runtime cost.
So, if you want the fastest possible code, you should be careful with std::function. For that reason the first variant is the fastest (on today's compilers):
int functor_by_value(functor_type x) {
return x(1);
}
It simply passes a pointer to a function.
When stateful lambdas are involved you have only two options. Either pass the lambda as a template argument, or convert to std::function. Hence, if you want the fastest code possible with lambdas (in today's compilers), you'd pass the function as a templated argument.
Since a lambda function may have a big state, passing it around may copy the big state (when copy elision is not possible). GCC will construct the lambda directly on the parameter list (with no copy), but a nested function will invoke a copy constructor for the lambda. To avoid that, either pass it by const reference (in that case it can't be mutable), or by rvalue reference:
template<class Func>
void run2(const Func & f)
{
std::cout << "Running\n";
f();
}
template<class Func>
void run(const Func & f)
{
run2(f);
}
int main()
{
run([s=BigState()]() { std::cout << "apply\n"; });
return 0;
}
Or:
template<class Func>
void run2(Func && f)
{
f();
}
template<class Func>
void run(Func && f)
{
run2(std::forward<Func>(f));
}
int main()
{
run([s=BigState()]() { std::cout << "apply\n"; });
return 0;
}
Without using references, the BigState() will be copied when the lambda is copied.
UPDATE:
After reading the question again I see that it wants to restrict the signature
template<typename Func,
typename = std::enable_if_t<
std::is_convertible_v<decltype(Func(1)), int>>>
void run2(const Func & f)
{
std::cout << "Running\n";
f();
}
This will restrict it to any function that can accept int (possibly with an implicit cast), and returns an int or any type that is implicitly cast to int. However, if you want to accept only function-like objects that accept exactly int and return exactly int you can see if the lambda is convertible to std::function<int(int)>

C++ How to bind and invoke a templated type method

I'm trying to understand the syntax to bind to a templated type's method. This seemed similar to my question, but didn't seem to give an example of binding and calling a templated type method.
Here's my code sample:
#include <functional>
#include <iostream>
using namespace std;
void DidSomething(int x)
{
cout << "Did something x = " << x << endl;
}
template <typename T>
class Outer
{
public:
void StartSomething()
{
Inner inner;
// below lines cause
// error C2893 Failed to specialize function template
//'unknown-type std::invoke(_Callable &&,_Types &&...)'
auto fnGlobal = std::bind(&::DidSomething);
inner.DoOneThing(fnGlobal);
auto fnMethod = std::bind(&Outer<T>::DidSomething, this);
inner.DoOneThing(fnMethod);
}
void DidSomething(int x)
{
cout << "Did something x = " << x << endl;
}
// example typedef, the actual callback has a lot of args (5 args)
typedef std::function<void(int)> DidSomethingCallback;
private:
class Inner
{
public:
void DoOneThing(DidSomethingCallback fnDidSomething)
{
fnDidSomething(3);
}
};
T t;
};
int main()
{
Outer<bool> outer;
outer.StartSomething();
return 0;
}
std::bind requires you to specify placeholders for unbound arguments so that the return type will know how many arguments to expect and where to pass them to. Hence you must write:
auto fnGlobal = std::bind(&::DidSomething, std::placeholders::_1);
to tell it that fnGlobal takes one argument and should call ::DidSomething with that one argument. Otherwise, fnGlobal will take no arguments. Likewise
auto fnMethod = std::bind(&Outer<T>::DidSomething, this, std::placeholders::_1);
will make fnMethod take one argument, call it x, then call this->DidSomething(x). Without the placeholder, fnMethod will take no arguments.
The clunkiness of std::bind makes it desirable to avoid using it in many cases. In the first case, it suffices to write
// the & is optional
auto fnGlobal = ::DidSomething;
to make fnGlobal a normal function pointer. In the second case, a lambda can be used:
auto fnMethod = [this](int x) { DidSomething(x); };
You are using std::bind the wrong way. You need to pass the corresponding number of arguments to be bound or placeholders as it may be when you create a std::bind object. Change:
auto fnGlobal = std::bind(&::DidSomething);
inner.DoOneThing(fnGlobal);
auto fnMethod = std::bind(&Outer<T>::DidSomething, this);
inner.DoOneThing(fnMethod);
to:
auto fnGlobal = std::bind(&::DidSomething, std::placeholders::_1);
inner.DoOneThing(fnGlobal);
auto fnMethod = std::bind(&Outer<T>::DidSomething, this, std::placeholders::_1);
inner.DoOneThing(fnMethod);
That should work

Storing and calling an unordered_map of member functions with varying signatures

I'm creating a class called MessageableObject, that can register its own member functions in a map. These functions can be called from outside by calling sendMessage, providing a return type as a template parameter, and passing the name of the function, as well as the paramters as variadic arguments. I've seen something very similar to this done before, only the functions were not member functions of the class storing them.
Below is the code I've written thus far, as well as a test case that should succeed.
#include <iostream>
#include <typeindex>
#include <typeinfo>
#include <unordered_map>
class MessageableObject
{
using _message_ptr = void(MessageableObject::*)(void);
std::unordered_map<const char*, std::pair<_message_ptr, std::type_index>> _message_map;
public:
MessageableObject()
{
}
template<typename F>
void addMessage(const char* name, F func)
{
auto type = std::type_index(typeid(func));
_message_map.insert(std::make_pair(name, std::make_pair((_message_ptr)func, type)));
}
template<typename R, typename... Args>
R sendMessage(const char* name, Args&&... args)
{
auto iter = _message_map.find(name);
assert(iter != _message_map.end());
auto type = iter->second;
auto func = reinterpret_cast<R(MessageableObject::*)(Args ...)>(type.first);
assert(type.second == std::type_index(typeid(func)));
return func(std::forward<Args>(args)...);
}
void foo()
{
std::cout << __FUNCTION__ << std::endl;
}
int bar(int i, int j)
{
std::cout << __FUNCTION__ << ' ' << i + j << std::endl;
return i + j;
}
};
int main()
{
MessageableObject obj;
obj.addMessage("foo", &MessageableObject::foo);
obj.addMessage("bar", &MessageableObject::bar);
obj.sendMessage<void>("foo");
int baz = obj.sendMessage<int>("bar", 1, 2);
return 0;
}
Currently, this code generates the following error twice:
C2064: term does not evaluate to a function taking n arguments
The first time with n being 0 for when I attempt to call foo, and n being 2 for when I attempt to call bar. Why are these errors occuring? And can I even implement this using the current syntax?
For reference, the version of this implementation that works on non-member functions can be found here: https://stackoverflow.com/a/33837343/962805
Any and all help is greatly appreciated. I'm not very knowledgeable on type erasure and member function binding. The intent for this is to create dynamic messaging a-la unity engine's GameObject.sendMessage function.
Update: As according to skypjack's answer below, the above solution will break if the message call contains a variable. It can be fixed by changing Args&&... in sendMessage to Args..., however this poses a new issue: if a message is added to the map that contains a reference parameter (such as int bar(int&, int)), it will not be able to be called implicitly. Calling sendMessage<int, int&, int>("bar", x, 2) will function as intended.
If you include <cassert> at the top of the file and use this:
return (this->*func)(std::forward<Args>(args)...);
Instead of this:
return func(std::forward<Args>(args)...);
It compiles.
I cannot say that it works for it looks to me you are fortunately avoiding an UB and it apparently works (that is a perfectly valid UB) would be more appropriate.
The problem is that bar has type:
int(MessageableObject::*)(int i, int j);
And you cast it cast to:
void(MessageableObject::*)(void);
Then you cast back it to it's correct type for you are invoking it as:
obj.sendMessage<int>("bar", 1, 2);
If you did instead this:
int x = 1;
obj.sendMessage<int>("bar", x, 2);
You would have performed a cast to:
int (MessageableObject::*)(int &i, int j);
Something similar would happen with a wrong return type. All these are UB. Therefore too weak a solution to use it in a production environment from my point of view.

A common type cast for lambda's and functions to reference later

Why is it the second example does not work? Is there a way I could get the second example to work while still type casting the lambda or function into a medium to reference later?
// Types I'm using
typedef void (*ANY_FUNC)(...);
typedef void (*VOID_FUNC)();
This works
void call_void( VOID_FUNC func) {
((ANY_FUNC)func)();
};
// ...
call_void([]() { /* do something */ });
This doesn't
template <typename fn>
void call_any( fn func ) {
((ANY_FUNC)func)();
};
// ...
call_any([]() { /* do something */ });
Please ignore the fact that you would never need to use the second example how it is now. It's only for demonstration (relative code).
Both examples work with function pointers instead of lambdas.
As long as you are declaring a template you can just use the incoming function object directly. Also, you should declare your function argument as a reference not as by value:
template <typename fn>
void call_any(fn&& func) {
func();
};
And if you want to call a function with arguments you can do:
template <typename fn, typename... Args>
void call_any_many(fn&& func, Args&&... args) {
func(std::forward<Args>(args)...);
};
Usage example:
int main ()
{
call_void([]() { std::cout << "Hello, void World!" << std::endl; });
call_any([]() { std::cout << "Hello, any World!" << std::endl; });
call_any_many([](int x) { std::cout << "Hello, any many World-" << x << "!" << std::endl; }, 1234);
return 0;
}
But if your intention is to store some function pointers and not to call them directly, I suggest using std::function from <functional> header. You can see some information and example from here: http://en.cppreference.com/w/cpp/utility/functional/function
For example:
#include <iostream>
#include <functional>
int main ()
{
std::function<void()> anyf = []() { std::cout << "Hello, any World!" << std::endl; };
std::function<void(int)> intf = [](int x) { std::cout << "Hello, any many World-" << x << "!" << std::endl; };
anyf();
intf(1234);
return 0;
}
I don't think any of them really works, except perhaps by chance on some compilers.
The difference with a lambda is that it is convertible to a function pointer, but it isn't one. The templated version will notice this difference, and fn is not deduced as VOID_FUNC.
Lambdas are implicitly convertible to function pointers (but only if they don't capture anything), so just change call_any's parameter to a function pointer:
void call_any(ANY_FUNC func)
{
(*func)();
}
You would need to call it with a lambda of the appropriate type:
call_any([](...) { /* ... */ });
But variable-length argument lists (aka varargs) are bad because they are as non-type-safe as you can get. Same with function pointers: they are non-object-oriented. You should think of an alternative mechanism, perhaps involving variadic templates and polymorphism (virtual methods)
The first is converting a lambda to a function pointer with corresponding argument and return types, then casting that to a vararg function, whereas the second is attempting to convert a lambda directly to a vararg function (i.e., a function without corresponding argument types).
The two conversions in the first example are allowed*, but the single conversion in the second is not.
* Note that the cast notation you use to convert between function pointer types ends up working like reinterpret_cast which states: "A function pointer can be explicitly converted to a function pointer of a different type. The effect of calling a function through a pointer to a function type (8.3.5) that is not the same as the type used in the definition of the function is undefined." And therefore the first example code has undefined behavior.

C++: How do I pass a function(without knowing its parameters) to another function?

I'm trying to create a function that will store and repeat another function given as a parameter for a specific amount of time or repeats given.
But when you want to pass a function as a parameter you have to know all of its parameters before hand.
How would I do if I wanted to pass the function as one parameter, and the parameters as another?
void AddTimer(float time, int repeats, void (*func), params); // I know params has no type and that (*func) is missing parameters but it is just to show you what I mean
Thanks in advance
The best that you can do is use std::function or boost::function as argument, together with std::bind or boost::bind to, well, bind the arguments with the function:
void foo() { std::cout << "foo" << std::endl; }
void bar( int x ) { std::cout << "bar(" << x << ")" << std::endl; }
struct test {
void foo() { std::cout << "test::foo" << std::endl; }
};
void call( int times, boost::function< void() > f )
{
for ( int i = 0; i < times; ++i )
f();
}
int main() {
call( 1, &foo ); // no need to bind any argument
call( 2, boost::bind( &bar, 5 ) );
test t;
call( 1, boost::bind( &test::foo, &t ) ); // note the &t
}
Note that there is something inherently wrong with passing a fully generic function pointer: how do you use it? How would the body of the calling function look like to be able to pass an undefined number of arguments of unknown types? That is what the bind templates resolve, they create a class functor that stores the function pointer (concrete function pointer) together with copies of the arguments to use when calling (note the &t in the example so that the pointer and not the object is copied). The result of the bind is a functor that can be called through a known interface, in this case it can be bound inside a function< void() > and called with no arguments.
dribeas' answer is correct as far as modern C++ is concerned.
For the sake of interest, there's also a simple lo-tech solution from the C world that as far as it goes, works in C++. Instead of allowing arbitrary parameters, define the function as void (*func)(void*), and make "params" void*. It's then the caller's job to define some struct that will contain the parameters, and manage its lifecycle. Usually the caller would also write a simple wrapper to the function that's really needed to be called:
void myfunc(int, float); // defined elsewhere
typedef struct {
int foo;
float bar;
} myfunc_params;
void myfunc_wrapper(void *p) {
myfunc_params *params = (myfunc_params *)p;
myfunc(params->foo, params->bar);
}
int main() {
myfunc_params x = {1, 2};
AddTimer(23, 5, myfunc_wrapper, &x);
sleep(23*5 + 1);
}
In practice you want to "fire and forget" timers, so if you use this scheme you may also need a way for the timer manage to free the userdata pointer once all firings have completed.
Obviously this has limited type safety. In principle in shouldn't matter, because whoever supplies the function pointer and user data pointer shouldn't have a great deal of difficulty ensuring that they match. In practice of course people find ways to write bugs, and ways to blame you because their compiler didn't tell them about the bugs ;-)
It's just an example how you could pass function pointer to another function, and then call it:
void AddTimer(float time, int repeats, void (*func)(int), int params)
{
//call the func
func(params);
}
void myfunction(int param)
{
//...
}
AddTimer(1000.0, 10, myfunction, 10);
Similarly, you can write your code if your function takes different type or/and numbers of parameters!
If there's really no rules about the function pointer at all, just use void*.
In C++11, things get really simple - you get everything you need to implement your timers.
The most concise way of passing bound function calls is by passing a functor generated using lambda syntax, e.g.: []{ std::cout << "Hello, world!" << std::endl; }. An object thus generated has a type known only to the compiler, but the type is convertible to std::function<void()>.
#include <functional>
#include <list>
#include <chrono>
#include <thread>
#include <iostream>
template <typename Clock = std::chrono::high_resolution_clock>
class Timers {
public:
using clock = Clock;
using duration = typename clock::duration;
using time_point = typename clock::time_point;
private:
struct Timer {
duration const period;
std::function<void()> const call;
int repeats;
time_point next;
Timer(duration $period, int $repeats, std::function<void()> && $call) :
period($period), call(std::move($call)), repeats($repeats) {}
};
std::list<Timer> m_timers;
public:
Timers() {}
Timers(const Timers &) = delete;
Timers & operator=(const Timers &) = delete;
template <typename C> void add(std::chrono::milliseconds period,
int repeats, C && callable)
{
if (repeats) m_timers.push_back(Timer(period, repeats, callable));
}
enum class Missed { Skip, Emit };
void run(Missed missed = Missed::Emit) {
for (auto & timer : m_timers) timer.next = clock::now() + timer.period;
while (! m_timers.empty()) {
auto next = time_point::max();
auto ti = std::begin(m_timers);
while (ti != std::end(m_timers)) {
while (ti->next <= clock::now()) {
ti->call();
if (--ti->repeats <= 0) {
ti = m_timers.erase(ti);
continue;
}
do {
ti->next += ti->period;
} while (missed == Missed::Skip && ti->next <= clock::now());
}
next = std::min(next, ti->next);
++ ti;
}
if (! m_timers.empty()) std::this_thread::sleep_until(next);
}
}
};
int main(void)
{
Timers<> timers;
using ms = std::chrono::milliseconds;
timers.add(ms(1000), 2, []{ std::cout << "Hello, world!" << std::endl; });
timers.add(ms(100), 20, []{ std::cout << "*" << std::endl; });
timers.run();
std::cout << std::endl;
return 0;
}