Search code examples
c++function-pointers

How to get function pointer from many functions and pass args to it?


I have many defined functions as follows, all return an int

int fn1(int x) {
    return x;
}

int fn2(std::string x, int y, std::string z) {
    // process string x and z
    int x1 = process(x);
    int z1 = process(z);
    return x1 + y + z1;
}

// ... and many more similar functions

For some reasons, I need to implement a wrapper to call the above functions by function names,

int wrapper(std::string fn_name, some_struct_t data, std::vector<std::string> field_names) {
    a_fn_ptr_type fn_ptr = nullptr; // <q1>: is this a right way to do?

    // by fn_name, decide which fn to call
    if (fn_name == "fn1") {
        fn_ptr = &fn1;
    }
    if (fn_name == "fn2") {
        fn_ptr = &fn2;
    }
    ...

    // given field_names, get the field from data, pass them to fn_ptr as args
    for (auto field_name: field_names) {
        std::any value = get_from_data(data, field_name, field_type); // field_type will be updated by this call, so that we know the value type.
        
        // <q2>: but how to pass each value as arg to fn_ptr here?
         
    }
}

The above code demonstrate what I want to achieve, and I have 2 questions (as pointed by <q1> and <q2>).

I'm not sure if the code is the right way to go, hope to get some advice from people, thanks!


Solution

  • Inspired by the comments:

    A wrapper that takes some_struct_t data, std::vector<std::string> field_names. Assuming a

    template <typename T>
    T get_from_data(some_struct_t, std::string);
    

    You have a function type

    using func_t = std::function<int(const some_struct_t &, const std::vector<std::string>&)>;
    

    which you can instantiate from functions via

    template <typename... Args, size_t... Is>
    auto wrap_impl(int(*func)(Args...), std::index_sequence<Is...>)
    {
        return [func](const some_struct_t & data, const std::vector<std::string>& field_names)
            { return func(get_from_data<Args>(data, field_names.at(Is))...); };
    }
    
    template <typename... Args>
    func_t wrap(int(*func)(Args...))
    {
        return wrap_impl(func, std::index_sequence_for<Args...>{});
    }
    

    and then you can have a

    std::map<std::string, func_t> functions;