Search code examples
c++boostfunction-pointersbindboost-bind

boost::bind with null function pointers


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());
}

Solution

  • 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().