Suppose that I have a function template that accepts arbitrary function object as an argument:
template<typename F>
// func is a function object
void do_something(F func) {
// Do something with func
}
I also have an ordinary function:
int f(int x) {
return 2 * x;
}
And I want to pass f as an argument to do_something. However, when I do it, do_something is instantiated with F = int (*)(int), and calls to func inside do_something result in run-time indirection through function pointer. What I want is to instantiate do_something specifically to call f, rather than any function with the same signature. I could achieve this with a lambda expression:
do_something([](int x) -> int { return f(x); });
In this case, do_something will be instantiated with F being a new closure type, and no pointer indirection will happen at run time. But this code doesn't look good. Is there a more elegant way to achieve this?
Related
See the code below
queue<function<void()> > tasks;
void add_job(function<void(void*)> func, void* arg) {
function<void()> f = bind(func, arg)();
tasks.push( f );
}
func is the function I want to add to the tasks which has argument is arg.
How can I do to use std::bind to bind its argument so that it can be assigned to the object of std::function<void()>?
How can I do to use std::bind to bind its argument so that it can be assigned to the object of function<void()>?
The std::bind returns an unspecified callable object, which can be stored in the std::function directly. Therefore you required only
function<void()> f = bind(func, arg); // no need to invoke the callable object
tasks.push( f );
However, I would recommend using lambdas (since C++11) instead of std::bind.
Secondly, having global variables are also not a good practice. I would propose the following example code. Let the compiler deduce the type of the passed functions and their (variadic) arguments (function-template).
template<typename Callable, typename... Args>
void add_job(Callable&& func, Args const&... args)
{
// statically local to the function
static std::queue<std::function<void()>> tasks;
// bind the arguments to the func and push to queue
tasks.push([=] { return func(args...); });
}
void fun1(){}
void fun2(int){}
int main()
{
add_job(&fun1);
add_job(&fun2, 1);
add_job([]{}); // passing lambdas are also possible
}
See a demo in
Just bind it, don't execute it.
function<void()> f = bind(func, arg);
tasks.push( f );
I'm attempting to make a template function that takes a function as a parameter and the parameter function has arguments for the template to deduce.
Example time:
Here is a function that accepts a fixed function type and works
void func_a(void(*func)(int)) {
func(1);
}
int main() {
auto f = [](int x) -> void { printf("%i\n", x); };
func_a(f);
return 0;
}
Here is what I want to do, expanding on the first example (this won't compile)
template <typename... T>
void func_b(void(*func)(T...)) {
func(1);
}
int main() {
auto f = [](int x) -> void { printf("%i\n", x); };
func_b(f); // neither of
func_b<int>(f); // these work
return 0;
}
Ideally I'd like func_b to accept both a regular function and a lambda function like func_a does, but with template magics.
Unfortunately, template deduction doesn't work well with implicit conversions. However, you can convert the lambda explicitly into a function pointer type. The shortest, but somewhat confusing way to do that is to apply unary + operator:
func_b(+f);
Or you could use the more intuitive, but also verbose and DRY-violating cast operation:
func_b(static_cast<void(*)(int)>(f));
But perhaps, you'll want to simply accept any callable type, instead of only function pointers:
template <class Fun>
void func_c(Fun&& func) {
func(1);
}
This works fine with lambdas. No conversions involved.
func_c(f);
And it also works for capturing lambdas (that cannot be converted to function pointers), std::function and function objects such as those defined in <functional>.
here you have some options that work:
#include <functional>
template <typename T>
void func_b(T&& func) {
func(1);
}
template <typename... T>
void func_c(std::function<void(T...)> func) {
func(1);
}
template <typename... T>
void func_d1(std::function<void(T...)> func) {
func(1);
}
template<typename... Params>
using fun = std::function<void(Params...)>;
template <typename T, typename... P>
void func_d(T& func) {
func_d1(fun<P...>(func));
}
int main() {
auto f = [](int x) { printf("%i\n", x); };
func_b(f);
func_b(std::function<void(int)>(f));
func_c(std::function<void(int)>(f));
func_d<decltype(f),int>(f);
return 0;
}
The issue is: A lambda is not a function pointer or std::function-object.
func_b uses perfect forwarding so T will be the type of the lambda not a std::function object.
For func_c. You should not convert a lambda to a c-style function pointer. A std::function object is able to do this conversion but only explicitly (by design) so you need to explicitly convert them.
func_d (and func_d1) combine the other aspects. It forwards the lambda and makes a std::function-object explicitly out of it though it needs an additional template parameter.
I've been trying to come up with a templated function that generalizes the bounce procedure when dealing with C APIs that use function pointer callbacks.
I've mostly figured it out and have a working system, but I'm wondering if there is a way to clean up the final step.
Imagine you have an API that takes a function pointer and a user data pointer. You want to use an instance method as the callback target. This requires a "bounce" function that reinterprets the user data pointer as an instance pointer and calls the method with the rest of the arguments.
The following example code works:
#include <cstdio>
class Foo {
public:
Foo(int val) : val_(val) { }
void baz(int v) const
{
printf("baz %d\n", v + val_);
}
private:
int val_;
};
// Templated bounce function
template<class T, class Method, Method m, class Ret, class ...Args>
static Ret bounce(void *priv, Args... args)
{
return ((*reinterpret_cast<T *>(priv)).*m)(args...);
}
#define BOUNCE(c, m) bounce<c, decltype(&c::m), &c::m>
// Callback simulator
void call_callback(void (*func)(void *, int), void *priv, int v)
{
if (func) {
func(priv, v);
}
}
// Main Entry
int main()
{
Foo bar(13);
call_callback(&bounce<Foo, decltype(&Foo::baz), &Foo::baz>, &bar, 10);
call_callback(&BOUNCE(Foo, baz), &bar, 11);
return 0;
}
Basically I'm looking for a way to clean up the usage. The macro works but I'm trying to instead find some type of helper function that can just take a method pointer parameter like &Foo::baz and deduce all the parameters. Something like a bounce_gen(&Foo::baz) that would return a pointer to the actual bounce function.
It has been a fun exercise, but I can't quite get the last piece.
The type of a member function pointer contains the class type and the function signature. So, you can let template function argument deduction handle this for you:
template<class T, class Method, class ...Args>
static auto bounce(Method T::*func, T* priv, Args... args) -> decltype((priv->*m)(args...))
{
return (priv->*m)(args...);
}
More convenient might be to either use std::bind or a lambda to completely hide the fact that it is a member function call:
template<class Func, class ...Args>
static auto bounceCallable(Func func, Args... args) -> decltype(func(args...))
{
return func(args...);
}
And you would call it like this:
call_callback([&bar](int v){bar.baz(v);}, 11);
With a lambda, you have a syntax nicer than with std::bind, but it comes at the cost of having to repeat the signature.
I am passing a pointer to function into a function template:
int f(int a) { return a+1; }
template<typename F>
void use(F f) {
static_assert(std::is_function<F>::value, "Function required");
}
int main() {
use(&f); // Plain f does not work either.
}
But the template argument F is not recognized by is_function to be a function and the static assertion fails. Compiler error message says that F is int(*)(int) which is a pointer to function. Why does it behave like that? How can I recognize the function or pointer to function in this case?
F is a pointer to function (regardless of whether you pass f or &f). So remove the pointer:
std::is_function<typename std::remove_pointer<F>::type>::value
(Ironically, std::is_function<std::function<FT>> == false ;-))
This is a followup question to my previous question.
#include <functional>
int foo(void) {return 2;}
class bar {
public:
int operator() (void) {return 3;};
int something(int a) {return a;};
};
template <class C> auto func(C&& c) -> decltype(c()) { return c(); }
template <class C> int doit(C&& c) { return c();}
template <class C> void func_wrapper(C&& c) { func( std::bind(doit<C>, std::forward<C>(c)) ); }
int main(int argc, char* argv[])
{
// call with a function pointer
func(foo);
func_wrapper(foo); // error
// call with a member function
bar b;
func(b);
func_wrapper(b);
// call with a bind expression
func(std::bind(&bar::something, b, 42));
func_wrapper(std::bind(&bar::something, b, 42)); // error
// call with a lambda expression
func( [](void)->int {return 42;} );
func_wrapper( [](void)->int {return 42;} );
return 0;
}
I'm getting a compile errors deep in the C++ headers:
functional:1137: error: invalid initialization of reference of type ‘int (&)()’ from expression of type ‘int (*)()’
functional:1137: error: conversion from ‘int’ to non-scalar type ‘std::_Bind<std::_Mem_fn<int (bar::*)(int)>(bar, int)>’ requested
func_wrapper(foo) is supposed to execute func(doit(foo)). In the real code it packages the function for a thread to execute. func would the function executed by the other thread, doit sits in between to check for unhandled exceptions and to clean up. But the additional bind in func_wrapper messes things up...
At the beginning, please let me introduce 2 key points:
a: When using nested std::bind, the inner std::bind is evaluated first, and the return value will be substituted in its place while the outer std::bind is evaluated. That means std::bind(f, std::bind(g, _1))(x) executes as same as f(g(x)) does. The inner std::bind is supposed to be wrapped by std::ref if the outer std::bind wants a functor rather than a return value.
b: The r-value reference cannot be correctly forwarded to the function by using std::bind. And the reason has already been illustrated in detail.
So, let's look at the question. The most importance function here might be func_wrapper which is intended to perform 3 purposes:
Perfect forwarding a functor to doit function template at first,
then using std::bind to make doit as a closure,
and letting func function template execute the functor returned by std::bind at last.
According to point b, purpose 1 cannot be fulfilled. So, let's forget perfect forwarding and doit function template has to accept a l-value reference parameter.
According to point a, purpose 2 will be performed by using std::ref.
As a result, the final version might be:
#include <functional>
int foo(void) {return 2;}
class bar {
public:
int operator() (void) {return 3;};
int something(int a) {return a;};
};
template <class C> auto func(C&& c) -> decltype(c()) { return c(); }
template <class C> int doit(C&/*&*/ c) // r-value reference can't be forwarded via std::bind
{
return c();
}
template <class C> void func_wrapper(C&& c)
{
func(std::bind(doit<C>,
/* std::forward<C>(c) */ // forget pefect forwarding while using std::bind
std::ref(c)) // try to pass the functor itsself instead of its return value
);
}
int main(int argc, char* argv[])
{
// call with a function pointer
func(foo);
func_wrapper(foo); // error disappears
// call with a member function
bar b;
func(b);
func_wrapper(b);
// call with a bind expression
func(std::bind(&bar::something, b, 42));
func_wrapper(std::bind(&bar::something, b, 42)); // error disappears
// call with a lambda expression
func( [](void)->int {return 42;} );
func_wrapper( [](void)->int {return 42;} );
return 0;
}
But, if you really want to achieve purpose 1 and 2, how? Try this:
#include <functional>
#include <iostream>
void foo()
{
}
struct bar {
void operator()() {}
void dosomething() {}
};
static bar b;
template <typename Executor>
void run(Executor&& e)
{
std::cout << "r-value reference forwarded\n";
e();
}
template <typename Executor>
void run(Executor& e)
{
std::cout << "l-value reference forwarded\n";
e();
}
template <typename Executor>
auto func(Executor&& e) -> decltype(e())
{
return e();
}
template <bool b>
struct dispatcher_traits {
enum { value = b };
};
template <typename Executor, bool is_lvalue_reference>
class dispatcher {
private:
static void dispatch(Executor& e, dispatcher_traits<true>)
{
run(e);
}
static void dispatch(Executor& e, dispatcher_traits<false>)
{
run(std::ref(e));
}
public:
static void forward(Executor& e)
{
dispatch(e, dispatcher_traits<is_lvalue_reference>());
}
};
template <typename Executor>
void func_wrapper(Executor&& e)
{
typedef dispatcher<Executor,
std::is_lvalue_reference<Executor>::value>
dispatcher_type;
func(std::bind(&dispatcher_type::forward, std::ref(e)));
}
int main()
{
func_wrapper(foo); // l-value
func_wrapper(b); // l-value
func_wrapper(bar()); // r-value
func_wrapper(std::bind(&bar::dosomething, &b)); // r-value
func_wrapper([](){}); // r-value
}
Let me explain some points:
To reduce lots of return statements, changing functor signature from int() to void().
The 2 run() function templates are used to check whether the original functor parameter is perfect forwarded or not.
dispatcher_traits is going to map bool constant to type.
You'd better name dispatcher::forward to differ from dispatcher::dispatch or you have to invoke std::bind template with dispatcher::forward's signature.
Looking at this the second time now, and I think I have a plausable explanation for the first error you are seeing.
In this case, it's more helpful to look at the complete error and the template instantiations that lead up to it. The error printed by my compiler (GCC 4.4), for example, ends with the following lines:
test.cpp:12: instantiated from ‘decltype (c()) func(C&&) [with C = std::_Bind<int (*(int (*)()))(int (&)())>]’
test.cpp:16: instantiated from ‘void func_wrapper(C&&) [with C = int (&)()]’
test.cpp:22: instantiated from here
/usr/include/c++/4.4/tr1_impl/functional:1137: error: invalid initialization of reference of type ‘int (&)()’ from expression of type ‘int (*)()’
Now looking at this bottom-up, the actual error message seems correct; the types the compiler has deduced are incompatible.
The first template instantiation, at func_wrapper, clearly shows what type the compiler has deduced from the actual parameter foo in func_wrapper(foo). I personally expected this to be a function pointer, but it is in fact a function reference.
The second template instantiation is hardly readable. But messing around with std::bind a bit, I learned that the format of the textual representation GCC prints for a bind functor is roughly:
std::_Bind<RETURN-TYPE (*(BOUND-VALUE-TYPES))(TARGET-PARAMETER-TYPES)>
So tearing it apart:
std::_Bind<int (*(int (*)()))(int (&)())>
// Return type: int
// Bound value types: int (*)()
// Target parameter types: int (&)()
This is where the incompatible types start. Apparently, even though c in func_wrapper is a function reference, it turns into a function pointer once passed to std::bind, resulting in the type incompatibility. For what it's worth, std::forward doesn't matter at all in this case.
My reasoning here is that std::bind only seems to care about values, and not references. In C/C++, there's no such thing as a function value; there's only references and pointers. So when the function reference is dereferenced, the compiler can only meaningfully give you a function pointer.
The only control you have over this is your template parameters. You will have to tell the compiler that you're dealing with a function pointer from the start to make this work. It's probably what you had in mind anyways. To do that, explicitly specify the type you want for the template parameter C:
func_wrapper<int (*)()>(foo);
Or the more brief solution, explicitly take the function's address:
func_wrapper(&foo); // with C = int (*)()
I'll get back to you if I ever figure out the second error. :)