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?
boost::function
s as the boost::bind
return object is used with varying call signatures in a template function.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);
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());
}
Boost. Bind defines placeholders from _1 to _9. These placeholders tell boost::bind() to return a function object that expects as many parameters as the placeholder with the greatest number.
Can I always reliably set a function pointer to NULL in C and C++? Yes, in any conforming C or C++ implementation this will work.
Initializing a pointer to a function, or a pointer in general to NULL helps some developers to make sure their pointer is uninitialized and not equal to a random value, thereby preventing them of dereferencing it by accident.
A null pointer has a reserved value that is called a null pointer constant for indicating that the pointer does not point to any valid object or function. You can use null pointers in the following cases: Initialize pointers. Represent conditions such as the end of a list of unknown length.
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()
.
I'd create a wrapper object to do this. Something like the following
#include <boost/bind.hpp>
#include <boost/function.hpp>
#include <iostream>
int aFunction(int i, int j)
{
std::cout<<"In a Function"<<std::endl;
return i+j;
}
struct DefaultingFromFnPtr : public boost::function< int(int,int) >
{
explicit DefaultingFromFnPtr( int(*fn)(int,int) ) : fn_(fn) {}
int operator()(int i, int j) const
{
if (fn_!=NULL) return fn_(i, j);
return 7;
}
int(*fn_)(int,int);
};
template<typename T>
void do_stuff( T t )
{
std::cout<<"RETURNED "<<t()<<std::endl;
}
int main( int argv, const char** argc)
{
int(*mightBeNullFnPtr)(int,int) = NULL;
if( argv>1)
{
mightBeNullFnPtr = & aFunction;
}
int var1 = 10;
int var2 = 20;
do_stuff( boost::bind( DefaultingFromFnPtr( mightBeNullFnPtr ), var1, var2 ) );
}
Compile this and run it with no arguments and it sets mightBeNullFnPtr to NULL and calls do_stuff with a wrapper class, and so prints out 7. Run it with an argument and it will set mightByNullFnPtr to aFunction and calls do_stuff with that, printing out 30.
If you want more genericity you will need to template the DefaultingFromFnPtr wrapper class, but that should be pretty easy to do.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With