2

I have a several functions with varying types of arguments:

static void fn1(int* x, int* y);
static void fn2(int* x, int* y, int* z);
static void fn3(char* x, double y);
...

I'd like to create a new function that takes in a collection of function pointers, a collection of argument values, and executes each function in the collection, in sequence, with the correct argument values:

static void executeAlgorithm(
    vector<FN_PTR_TYPE> functionToExecute,
    map<FN_PTR_TYPE, FN_ARG_COLLECTION> args)
{
    // for each function in 'functionToExecute',
    // get the appropriate arguments, and call the
    // function using those arguments
}

What's the cleanest way to achieve this behavior?

4
  • 1
    The short answer is variadic templates and tuples. What have you tried so far? Commented Mar 20, 2018 at 17:31
  • 3
    Get rid of the map and make the vector a std::vector<std::function<void()>>; the arguments then just to into the function wrapper. Commented Mar 20, 2018 at 17:32
  • Use a language with less strict typing. Commented Mar 20, 2018 at 17:33
  • You could use a std::variant<void(*)(int*, int*), ...> but I don't think that would end up being clean... Commented Mar 20, 2018 at 17:35

1 Answer 1

2

Here is quite simple solution based on what @KerrekSB suggested in the comment. You basically std::bind a function and its args, and since you don't have to pass args any more your function becomes uniform std::function<void()> which is easy to store in a container:

#include <iostream>
#include <vector>
#include <functional>

static void fn1(int x, int y)
{
    std::cout << x << " " << y << std::endl;
}

static void fn2(int x, int *y, double z)
{
    std::cout << x << " " << *y << " " << z << std::endl;
}

static void fn3(const char* x, bool y)
{
    std::cout << x << " " << std::boolalpha << y << std::endl;
}

int main()
{
    std::vector<std::function<void()>> binds;
    int i = 20;

    binds.push_back(std::bind(&fn1, 1, 2));
    binds.push_back(std::bind(&fn1, 3, 4));
    binds.push_back(std::bind(&fn2, 1, &i, 3.99999));
    binds.push_back(std::bind(&fn2, 3, &i, 0.8971233921));
    binds.push_back(std::bind(&fn3, "test1", true));
    binds.push_back(std::bind(&fn3, "test2", false));

    for (auto fn : binds) fn();
}

Demo: https://ideone.com/JtCPsj

1 2
3 4
1 20 3.99999
3 20 0.897123
test1 true
test2 false
Sign up to request clarification or add additional context in comments.

4 Comments

Great. This is what I want. Ideally, I wouldn't have a dependency on C++11, but it's not that big of a deal.
Thanks to you, and also to @KerrekSB for the great tip!
@Kirby: No problem, I'm glad someone else expanded it :-)
@Kirby: There's nothing in principle that stops you from implementing something like std::function in C++98. The main thing you'd miss would be the variadic bind, which you could replace with a more targeted special solution for your use case. In particular, you do not need a variadic specialization of std::function<T>, since you only ever need the case T = void().

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.