boost::bind with null function pointers

Matt Joiner picture Matt Joiner · Jan 6, 2010 · Viewed 7.4k times · Source

If the function pointer embedded in a boost::bind return object is NULL/nullptr/0, I need to take action other than calling it. How can I determine if the object contains a null function pointer?

Addenda

  1. I don't believe I can use and compare boost::functions as the boost::bind return object is used with varying call signatures in a template function.
  2. Simplified example:
template <typename BRO>
Retval do_stuff(BRO func, enum Fallback fallback)
{
    if (func == NULL)
    {
        return do_fallback(fallback);
    }
    else
    {
        return use_retval(func());
    }
}

do_stuff(boost::bind(FuncPtrThatMightBeNull, var1, var2), fallback);

Solution

Since the arity of the function in the callee does not change, I can "cast" the bind return object into a boost::function and call .empty()

Retval do_stuff(boost::function<Retval()> func, enum Fallback fallback)
{
    if (func.empty())
        return do_fallback(fallback);
    else
        return use_retval(func());
}

Answer

Georg Fritzsche picture Georg Fritzsche · Jan 6, 2010

You can either bind to a dummy function:

void dummy() { /* has differing behaviour */ }
// ...
boost::bind(&dummy)();

... or, assuming you're using Boost.Bind together with Boost.Function, return a default constructed function object and check for empty() before calling it:

typedef boost::function<void (void)> F;
F create() { return F(); }

void use() {
    F f = create();
    if(f.empty()) {
        /* ... */
    }
}

Regarding the update:
I still don't see what the problem with binding to a different function like the following would be:

template <typename BRO>
Retval do_stuff(BRO func)
{
    return func();
}

if(funcPtr) {
    do_stuff(boost::bind(&use_retval, boost::bind(funcPtr, a, b)));
} else {
    do_stuff(boost::bind(&do_fallback, fallback));
}

If you'd want to move that handling out of the calling code, you could emulate variadic template function to support variable arities:

template<class R, class T1> 
boost::function<R (T1)> 
bind_wrap(R (*fnPtr)(), T1& t1, Fallback fallback) {
    if(fnPtr) return boost::bind(&use_retval,  boost::bind(funcPtr, t1));
    else      return boost::bind(&do_fallback, fallback);
}

template<class R, class T1, class T2> 
boost::function<R (T1, T2)> 
bind_wrap(R (*fnPtr)(T1, T2), T1& t1, T2& t2, Fallback fallback) {
    if(fnPtr) return boost::bind(&use_retval,  boost::bind(funcPtr, t1, t2));
    else      return boost::bind(&do_fallback, fallback);
}

// ... etc. for all needed arities

do_stuff(bind_wrap(funcPtr, var1, var2, fallback));

... or you use the approach above to generate boost::function<> objects or your own wrappers and check for functor.empty() or similar in do_stuff().