Question

Can the following function pointer passing be simplified/improved with the use of boost::function and/or boost::bind?

void PassPtr(int (*pt2Func)(float, std::string, std::string))
{
   int result = (*pt2Func)(12, "a", "b"); // call using function pointer
   cout << result << endl;
}

// execute example code
void Pass_A_Function_Pointer()
{
   PassPtr(&DoIt);
}
Was it helpful?

Solution

You can use boost::function<> to make it possible using different types of callable objects as the function's input.

What follows is an example using C++11 (see the remarks after this example). This is how you would rewrite your function:

#include <functional>
#include <string>
#include <iostream>

void PassFxn(std::function<int(float, std::string, std::string)> func)
//           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
{
   int result = func(12, "a", "b"); // call using function object
   std::cout << result << std::endl;
}

These are a couple of functions to test it with:

int DoIt(float f, std::string s1, std::string s2)
{
    std::cout << f << ", " << s1 << ", " << s2 << std::endl;
    return 0;
}

int DoItWithFourArgs(float f, std::string s1, std::string s2, bool b)
{
    std::cout << f << ", " << s1 << ", " << s2 << ", " << b << std::endl;
    return 0;
}

struct X
{
    int MemberDoIt(float f, std::string s1, std::string s2)
    {
        std::cout << "Member: " << f << ", " << s1 << ", " << s2 << std::endl;
        return 0;
    }

    static int StaticMemberDoIt(float f, std::string s1, std::string s2)
    {
        std::cout << "Static: " << f << ", " << s1 << ", " << s2 << std::endl;
        return 0;
    }
};

And here is the test routine:

int main()
{
    PassFxn(DoIt); // Pass a function pointer...

    // But we're not limited to function pointers with std::function<>...

    auto lambda = [] (float, std::string, std::string) -> int
    {
        std::cout << "Hiho!" << std::endl;
        return 42;
    };

    PassFxn(lambda); // Pass a lambda...

    using namespace std::placeholders;
    PassFxn(std::bind(DoItWithFourArgs, _1, _2, _3, true)); // Pass bound fxn

    X x;
    PassFxn(std::bind(&X::MemberDoIt, x, _1, _2, _3)); // Use a member function!

    // Or, if you have a *static* member function...
    PassFxn(&X::StaticMemberDoIt);

    // ...and you can basically pass any callable object!
}

And here is a live example.

REMARKS:

You can easily change std::function<> into boost::function<> and std::bind<> into boost::bind<> if you are working with C++03 (in fact, Boost.Function is what inspired std::function<> and later became part of the Standard C++ Library). In this case, instead of including the <functional> header, you will have to include the boost/function.hpp and boost/bind.hpp headers (the latter only if you want to use boost::bind).

For a further example that should give you a feeling of the power that std::function<> / boost::function<> gives you through its ability of encapsulating any kind of callable object, also see this Q&A on StackOverflow.

OTHER TIPS

I assume you want to improve the functionality of PassPtr, rather than all of the sample code you gave. If you are using C++11 and can use lambda expressions, I would simplify it to just:

template <typename Func>
void PassPtr(Func f) {
  std::cout << f(12, "a", "b") << std::endl;
}

This will allow any callable object to be passed as f. The reason for taking the function by a deduced template type is to allow any lambdas that are passed to be inlined. Of course, this doesn't enforce any particular signature on the passed function (or that it should even be a callable object). For example, if you pass an int, you'll get some confusing compiler errors.

The alternative, using [boost|std]::function, is to do this:

void PassPtr(std::function<int(float, std::string, std::string)> f) {
  std::cout << f(12, "a", "b") << std::endl;
}

This will allow any kind of callable object to be passed, just as the above, but will probably not cause lambdas to be inlined.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top