How to pass std::function with different parameters to same function

15,215

Solution 1

It seems to work with variadic templates.

Something like:

template <typename ... Args>
void run_callback(std::function<void(Args...)> const & func, Args ... as) {
    try {
        func(as...);
    } catch(const std::exception& ex) {
        print_callback_error(ex.what());
    } catch(const std::string& ex) {
        print_callback_error(ex.c_str());
    } catch(...) {
        print_callback_error();
    }
}

or (maybe better to manage possible forwarding)

template <typename ... FArgs, typename ... Args>
void run_callback(std::function<void(FArgs...)> const & func,
                  Args && ... as) {
    try {
        func(std::forward<Args>(as)...);
    } catch(const std::exception& ex) {
        print_callback_error(ex.what());
    } catch(const std::string& ex) {
        print_callback_error(ex.c_str());
    } catch(...) {
        print_callback_error();
    }
}

Solution 2

I suggest to use a lambda function:

void run_callback(std::function<void()>& func) {
    try {
        func();
    } catch(const std::exception& ex) {
        print_callback_error(ex.what());
    } catch(const std::string& ex) {
        print_callback_error(ex.c_str());
    } catch(...) {
        print_callback_error();
    }
}

To call this function you should:

run_callback([]{ func_without_params(); });

or

run_callback([&]{ func_with_1_param(a); });

And so on

Share:
15,215
Griffort
Author by

Griffort

gfgdfg dfgfdg f gfdg dfgregre t tg fq53ji0t34j8t0 uj34g0ihvfpzshrgkih yh vdfogj8934hgf3-n0u 53g350gh 53u90gh39 h53g h 93gh93gh89reh g89-rey89gf g8e yg d9fhgdf yh9dhfg 34h89gy34hg hgrgh8rwhg8h9er ghrehngih89h3tu 9rgfh gfud hg8df gdfhgo fogdf.

Updated on June 05, 2022

Comments

  • Griffort
    Griffort almost 2 years

    I have three functions I'm looking to merge together.

    Each one takes an std::function as the first parameter, then executes it within a try/catch block.

    The issue is, there are three different types of functions. Functions with no parameters, those with one integer parameter, and those with two integer parameters. The ones with integer parameters also have their corresponding parameters passed through the original function.

    As one can see, each of the functions are nearly identical, so it would be nice if I could merge them all together. However, I'm unsure of anyway to setup a parameter that can receive any form of std::function and also rely on the fact it has been provided with corresponding data to use.

    Here are the functions:

    void run_callback(std::function<void()>& func) {
        try {
            func();
        } catch(const std::exception& ex) {
            print_callback_error(ex.what());
        } catch(const std::string& ex) {
            print_callback_error(ex.c_str());
        } catch(...) {
            print_callback_error();
        }
    }
    
    void run_callback_int(std::function<void(int)>& func, int data) {
        try {
            func(data);
        } catch(const std::exception& ex) {
            print_callback_error(ex.what());
        } catch(const std::string& ex) {
            print_callback_error(ex.c_str());
        } catch(...) {
            print_callback_error();
        }
    }
    
    void run_callback_intint(std::function<void(int, int)>& func, int data1, int data2) {
        try {
            func(data1, data2);
        } catch(const std::exception& ex) {
            print_callback_error(ex.what());
        } catch(const std::string& ex) {
            print_callback_error(ex.c_str());
        } catch(...) {
            print_callback_error();
        }
    }
    

    Any suggestions would be greatly appreciated!

  • WhozCraig
    WhozCraig about 6 years
    I'll uptick this anyway, but you may want to add perfect forwarding to this. Just saying.
  • max66
    max66 about 6 years
    @liliscent - D'Oh! Thanks!
  • max66
    max66 about 6 years
    @WhozCraig - you're right but I'm in doubt: how to write references for the type arguments of the std::function?
  • Griffort
    Griffort about 6 years
    Absolute perfection, I knew there had to be some way! Do you have any recommendations on where I can learn about the "Args ..." stuff? (Sorry, I'm not certain on the correct terminology, but that stuff that letting you specify an indefinite amount of parameters and then referencing it in different ways within the function?)
  • Arnav Borborah
    Arnav Borborah about 6 years
    @Griffort They are called variadic templates. Googling them up brings up a lot of good references.
  • max66
    max66 about 6 years
    @Griffort - the Args... stuff are "variadic templates"; it's a fundamental innovation of C++11 (they are not present in C++98). I don't know what suggest to learn they but if you find a good resource for C++11, do you find a good resource for variadic templates.
  • max66
    max66 about 6 years
    @WhozCraig - I've added another example to add forwarding but I've also added another variadic template list for std::function. It seems to me that, using perfect forwarding, can be a mismatch in the two types lists. What do you think?
  • max66
    max66 about 6 years
    @Griffort - following the WhozCraig's suggestion, I've added another example. It's a little more complicated but use another important C++11 feature: "perfect forwarding"; look also for "rvalues references", "lvalues references" and "move semantic".
  • Griffort
    Griffort about 6 years
    @max66 Oh my, that looks even scarier. I'll try and see if I can come to learn it though. Safety aside, would one or the other be better for performance? Or are they generally going to be the same speed?
  • max66
    max66 about 6 years
    @Grifford - in your case (a function that receive only simple integers) there isn't difference. More in general, the second form is a lot better of the first because permit the activation of move semantics, when appropriate. An the move semantics is a great performance improvement for C++11.