2

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);
}
pingu
  • 8,719
  • 12
  • 50
  • 84
  • 1
    It depends what kind of answer you're looking for! Of course, all of the above can be simplified to `cout << DoIt(12, "a", "b") << endl;`, but I guess that's not what you're looking for. That said, there are no obvious opportunities to take advantage of Boost features here, as you're calling a pure function pointer, not a function object, etc. – Oliver Charlesworth Mar 10 '13 at 14:30
  • It can be improved in that you then can use any member function or lambdas (if you have C++11 compatible compiler) too, not only plain function or static member function. And of course, with `boost::bind` (or [`std::bind`](http://en.cppreference.com/w/cpp/utility/functional/bind)) you can "bind" any number of arguments before passing the function object around. – Some programmer dude Mar 10 '13 at 14:31
  • What's fixed and what can change? If the signatures of `PassPtr` and `DoIt` are fixed then no, the code is as simple as it gets. – CB Bailey Mar 10 '13 at 14:32
  • @Charles - all thats fixed is that I wish to pass a pointer to a function, for example DoIt, and have it called. Everything else can change. – pingu Mar 10 '13 at 14:34
  • If you want to pass a pointer to a function, then you are doing that in the simplest way possible. – CB Bailey Mar 10 '13 at 14:42

2 Answers2

7

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.

Community
  • 1
  • 1
Andy Prowl
  • 124,023
  • 23
  • 387
  • 451
  • Thats great! could you add one further example before I mark as answered. How would the syntax look for when DoIt is a member function being passed? – pingu Mar 10 '13 at 14:55
4

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.

Joseph Mansfield
  • 108,238
  • 20
  • 242
  • 324