How to pass a function pointer when the pointee has optional parameters? - c++

I'm trying to pass a function pointer as a parameter of another function, but the function pointer may or may not itself have an argument (making it different from the other questions I searched for).
The code works as is, but MY problem is that I was trying to use a single function and pass in each different function pointer, but what I have below is 3 different functions to pass each function pointer. I'd like to get rid of the 3 different function definitions as they are all the same with the exception of the passed in function pointer (so basically, 3 copies of execute_func() definitions). Here's what I have so far but this doesn't seem right that I should need three execute_func() calls.
class A { ... };
class B { ... };
class Test {
private:
std::function<void()> fp;
std::function<void(MyA &)> fp;
std::function<void(MyB &)> fp;
// ...
};
// Here I create a function pointer for each of my calls.
Test::Test() {
fp = std::bind(&Test::do_this, this);
fp_a = std::bind(&Test::do_a, this, std::placeholders::_1);
fp_b = std::bind(&Test::do_b, this, std::placeholders::_1);
}
// Here my intention was to have only 1 execute_func() call and I would
// pass in the pointer to the function that I want to call.
Test::test_it()
{
A a;
B b;
execute_func(fp);
execute_func(fp_a, a);
execute_func(fp_b, b);
}
// I was hoping to only need one function, but so far
// have needed 3 functions with diff signatures to make it work.
bool Test::execute_func(std::function<void()> fp) {
// ... more code here before the fp call
fp();
// ... them more common code here.
}
bool Test::execute_func(std::function<void(MyA &)> fp, MyA &a) {
// ... more common code here
fp(a);
// ... and more common code here
}
bool Test::execute_func(std::function<void(MyB &)> fp, MyB &b) {
// ... more common code here
fp(b);
// ... and more common code here.
}
// And of course the execute_func() calls call these members as passed in.
bool Test::do_this() { ... }
bool Test::do_a(MyA &a) { ... }
bool Test::do_b(MyB &b) { ... }
Thoughts on where I'm going wrong?

To do this you can use a variadic template.
template<typename Ret, typename... Args>
bool Test::execute_func(Ret fp(Args&&...), Args&&... args)
{
// do stuff
fp(args...);
// do more stuff
}
I'm using an ordinary function pointer here instead of std::function, which is, IMO, baroque and wholly unnecessary (it's a relic from when C++ didn't have lambdas). But it's the same idea.
template<typename Ret, typename... Args>
bool Test::execute_func(const std::function<Ret(Args&&...)> &fp, Args&&... args) { }
Edit: Jarod42 points out that you can make it so it will work with both function pointers, std::function and any other callable object as follows:
template<typename Func, typename... Args>
bool Test::execute_func(Func &&fp, Args&&... args)
{
// do stuff
fp(args...);
// do more stuff
}
To make it even more generic you can use std::invoke to call fp instead of directly calling it, which additionally allows fp to be a member function or data member (with the instance pointer given in the first subsequent argument).
template<typename Func, typename... Args>
bool Test::execute_func(Func &&fp, Args&&... args)
{
// do stuff
std::invoke(fp, args...);
// do more stuff
}
The previous example could also equivalently be written
template<typename... InvokeArgs>
bool Test::execute_func(InvokeArgs&&... iargs)
{
// do stuff
std::invoke(iargs...);
// do more stuff
}

Related

Expanding on a Job/Worker multi-threading system in C++

I've been reading a tutorial by Ben Hoffman (https://benhoffman.tech/cpp/general/2018/11/13/cpp-job-system.html)
I've had a go at bashing together a version of the Job/Worker system he has, but instead of using void* for arguments then casting to a known struct, I've been trying to use variadic arguments. The idea is, a job takes in a "parent" to perform a method on, the function pointer to said method, and an Args... for the argument(s). However, I get an internal compiler error if I try to build. Here is the job class:
template <class T, typename... Args>
struct JobMemberFunc : IJob
{
JobMemberFunc(T* aParent, void (T::* f)(Args...), Args... Args)
{
parentObj = aParent;
func_ptr = f;
saved_args = ::std::make_tuple (::std::move(Args)...);
}
virtual bool invoke() override
{
if (!parentObj) { return false; }
(parentObj->*func_ptr)(::std::move(saved_args));
return true;
}
/** the object to invoke the function pointer on */
T* parentObj;
/** The function pointer to call when we invoke this function */
void (T::* func_ptr)(Args...);
::std::tuple<Args...> saved_args;
};
struct CpuJob
{
IJob* jobPtr = nullptr;
};
Then there's the AddJob method, where the internal compiler error is actually happening.
template <typename T, typename... Args>
void AddJob(T* aParent, void(T::* func_ptr)(Args...), Args... args)
{//This curly bracket is where the internal compiler error happens
CpuJob aJob = {};
JobMemberFunc<T, Args...>* jobPtr = new JobMemberFunc<T, Args...>(aParent, func_ptr,
std::forward<Args>(args)...);
aJob.jobPtr = jobPtr;
locklessReadyQueue.enqueue(aJob);
}
More than happy to be told this is a bad/wrong way of trying to do it anyway. I have thought about doing away with it and having a standardized argument list or doing something polymorphic but I really wanna make this work so I can literally ask the job system to do anything I like.
Thanks!
std::function<void()> (in combination with lambdas) already do what you're trying to do with JobMemberFunc.
void AddJob(std::function<void()>&& job)
{
locklessReadyQueue.enqueue(std::move(job));
}
With this you can submit any function call as a job.
For example, a call some_obj.some_method(some_arg) becomes:
AddJob([&] { some_obj.some_method(some_arg); });
No more ugly pointer-to-member stuff...
You can find more complete thread pooling examples here: Thread pooling in C++11

C++ template function that takes a function type with specific return type

I am doing some magic with templates in c++ and thought of trying something.
In this case I wrote a naive generic list implementation with a List Type and a ListElement Type that contains the data.
Now I already wrote a templated "for each call" function, that takes an arbitrary member function type of the type stored in the list with an arbitrary argument list and calls that member function on each element in the list with the given arguments:
template<typename function, typename ... arguments>
void for_each_call(function call, arguments ... args)
{
for(ListElement * current = this->first; current != nullptr; current = current->next)
{
(current->value->*call)(args ...);
}
}
The problem with this is that I can not "react" to the return values of the called function. Though I do NOT want to implement a .map functionality!
Now I want to implement a "for each call until" that calls a function upon the values in the list until a call returns "true" and then stops. For that I need to limit the functions inserted as a template parameter to functions of any type that specifically return a boolean. I typed around until the compiler stopped complaining and got this:
template<bool (*function), typename ... arguments>
void for_each_call_until(arguments ... args)
{
for(ListElement * current = this->first; current != nullptr; current = current->next)
{
if((current->value->*function)(args ...)) break;
}
}
What is happening here, is this the right way, and if not, what is the right way?
EDIT: As some people recommend using functions from the std:: namespace: In these little training sessions I try to avoid the std:: like a plague, as if I would want to use std:: I would not write these little standardimplementations of stuff like lists, vectors or mappings myself but use std:: or boost::
First of all, this approach is unnecessarily limiting:
(current->value->*call)(args ...);
If you require a member function, there's only a small handful of operations you can actually do. If the caller wants to do more, they're kind of screwed. Instead, generalize and pass current->value as the first argument:
template<typename function, typename ... arguments>
void for_each_call(function call, arguments ... args)
{
for(ListElement * current = this->first; current != nullptr; current = current->next)
{
call(current->value, args...);
}
}
This works on all the cases as before - where you would pass &Class::mem before now instead you pass std::mem_fn(&Class::mem) - but now you can pass any kind of callable too.
Now onto your main question. You don't have to do anything different. Just use the result of call():
template<typename function, typename ... arguments>
void for_each_call(function call, arguments ... args)
{
for(ListElement* current = this->first; current != nullptr; current = current->next)
{
if (call(current->value, args...)) {
break;
}
}
}
That's it. If the user provides a callable that doesn't return something contextually convertible to bool, they'll get a compile error. Why limit to just returning bool?
If you really do need really just bool, throw in a static assert:
template<typename function, typename ... arguments>
void for_each_call(function call, arguments ... args)
{
static_assert(std::is_same<decltype(call(this->first->value, args...)), bool>::value, "Must be bool!");
// rest...
}
Note: You probably want to take your arguments... by reference to const to avoid lots of copies.
Starting from this, just to show you how member function pointers work:
class Foo {
public:
bool test() { return true; }
};
/// The function takes a member function of a class T and its arguments.
template<typename T, typename... Args>
void for_each_call_until(bool (T::*member_function)(Args...),
Args&& ... args) {
T obj; // Instantiate an example object.
bool rts = (obj.*member_function)(std::forward<Args>(args)...);
if (rts == false) { // Check for the result of the member function
// close
}
// ...
}
Your function could be something like:
template<typename... Args>
void for_each_call_until(bool (ListElement::*member_function)(Args...),
Args&& ... args) {
for ( /* iteration over pointers */ ) {
bool rts = (current->*member_function)(std::forward<Args>(args)...);
if (rts == false) {
// break
}
// ...
}
}
A simple solution involves using partial specialization to force a compilation error:
#include <type_traits>
#include <utility>
template<typename T> struct is_bool;
template<> struct is_bool<bool> { typedef int value; };
template<typename function, typename ... arguments>
void for_each_call(function call, arguments && ... args)
{
typedef decltype(call(std::forward<arguments>(args)...)) ret_type;
typedef typename is_bool<ret_type>::value x;
call(std::forward<arguments>(args)...);
}
bool foo(int, int) {} // Compiles
// int foo(int, int) {} // Does not compile
int main()
{
for_each_call(foo, 4, 2);
return 0;
}

C++ templated callback bounce function

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.

How can I implement a function for invoking any (arbitrary) function with its (arbitrary) arguments?

I would like to have the following:
void foo(
/* something representing a function f */,
/* arguments a1, a2, etc. in some form */ )
{
/* magic - invoke f(a1, a2, etc.)*/
}
/* ... */
void bar(float f, char* s);
void baz(int i);
/* etc. */
int main() {
/* ... */
foo(bar, SomeKindOfTransformationOrNoneAtAll(f, s));
foo(baz, SomeKindOfTransformationOrNoneAtAll(i));
/* etc. */
}
Can I implement foo()? That is, can I write a function which takes an arbitrary other function, and a bunch of arguments (varargs, or vector, or list, or what have you) and invokes the passed function with the passed arguments?
If this is possible, is there a library which facilitates it? Or some common idiom for it?
Note:
I do not want to bind the arguments to the function outside foo(), but rather inside it. So, foo() must take more than just a single function*/std::function/etc. parameter.
Variadic templates can indeed do this.
template<typename T, typename... Args> void foo(T func, Args&&... args) {
func(std::forward<Args>(args)...);
}
Then simply pass the arguments directly to foo. This is called perfect forwarding. However with lambdas it's really more idiomatic to bind them there.
template<typename T> void foo(T func) {
func();
}
int main() {
foo([] { baz(param1, param2); });
}
You can capture the params if they're not constants. This is a superior choice because you can convert the template easily into a non-template if you want, and the issue of parameter lifetime or not is dodged because the lambda user can capture however they need. You can take multiple objects this way instead of just one, as a variadic pack can only occur once. And finally, you don't have to shit around with making it pick a single function pointer thingie when using named functions.
What you seem to be looking for is std::bind.
So, something like :
void foo(std::function<void()> fun) {
fun();
}
foo(std::bind(bar, 0.1f, "abc"));
foo(std::bind(baz, 42));
If I understand correctly, you want to decide at the site of the caller what the function should be called with.
The simplest solution is to use a lambda with std::function:
void foo(std::function<void(void)> f) { // std::function has strong magic
// whatever you want here
f();
// whatever you want here
}
/* ... */
void bar(float f, char* s);
void baz(int i);
/* etc. */
int main() {
foo( [f, s]() { bar(f, s); } );
foo( [&i]() { baz(i) } );
/* etc. */
}

looping over all arguments of a function in C++

I want to do identical processing to a bunch of arguments of a function. Is there a way to loop over all arguments ? I am doing it the way represented in following code, but want to see if there is a compact way to do this.,
void methodA(int a1, int a2, int b1, double b2){
//.. some code
methodB(a1, f(a1));
methodB(a2, f(a2));
methodB(b1, f(b1));
methodB(b2, f(b2));
// more code follows ...
}
int f(int a){
// some function.
return a*10;
}
double f(double b){
return b/2.0;
}
You could use variadic templates:
template <typename T, typename ...Args>
void methodAHelper(T && t, Args &&... args)
{
methodB(t, f(t));
methodAHelper(std::forward<Args>(args)...);
}
void methodAHelper() { }
template <typename ...Args>
void methodA(Args &&... args)
{
// some code
methodAHelper(std::forward<Args>(args)...);
// some other code
}
You can possibly get rid of the && and the forwarding if you know that your methodB call doesn't know about rvalue references, that would make the code a bit simpler (you'd have const Args &... instead), for example:
methodAHelper(const T & t, const Args &... args)
{
methodB(t, f(t));
methodAHelper(args...);
}
You might also consider changing methodB: Since the second argument is a function of the first argument, you might be able to only pass the first argument and perform the call to f() inside the methodB(). That reduces coupling and interdependence; for example, the entire declaration of f would only need to be known to the implementation of methodB. But that's depends on your actual situation.
Alternatively, if there is only one overload of methodB whose first argument is of type T, then you could just pass a std::vector<T> to methodA and iterate over it:
void methodA(const std::vector<T> & v)
{
// some code
for (auto it = v.cbegin(), end = v.cend(); it != end; ++it)
methodB(*it, f(*it));
// some more code
}
int main() { methodA(std::vector<int>{1,2,3,4}); }
Yes there is, the concept you're looking for is called a variadic function.
Depending on what you are trying to do. The simplest thing might to revisit your function and see if it can take an array or std::vector as an argument. Might be much simpler that going the variadic route