Если указатель функции встраивается в a boost::bind
эхо-сигнал NULL
/nullptr
/0
, Я должен принять меры кроме вызова его. Как я могу определить, содержит ли объект пустой указатель функции?
boost::function
s как boost::bind
эхо-сигнал используется с переменными подписями вызова в шаблонной функции.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);
Так как арность функции в вызываемом не изменяется, я могу "бросить" связывать эхо-сигнал в a boost::function
и звоните .empty()
Retval do_stuff(boost::function<Retval()> func, enum Fallback fallback)
{
if (func.empty())
return do_fallback(fallback);
else
return use_retval(func());
}
можно либо привязать к фиктивной функции:
void dummy() { /* has differing behaviour */ }
// ...
boost::bind(&dummy)();
... либо, предполагая, что вы используете Boost.Bind
вместе с Boost.Function
, вернуть объект построенной по умолчанию функции и проверить empty()
перед вызовом:
typedef boost::function<void (void)> F;
F create() { return F(); }
void use() {
F f = create();
if(f.empty()) {
/* ... */
}
}
Относительно обновления:
.
Я до сих пор не понимаю, в чем проблема с привязкой к другой функции вроде:
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));
}
Если бы вы захотели перенести эту обработку из вызывающего кода, то можно было бы эмулировать вариадическую шаблонную функцию для поддержки переменных 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));
. либо вы используете вышеприведенный подход для генерации объектов boost::function<>
или собственных оберток и проверки на наличие functor.empty()
или аналогичной функции в do_stuff()
.
Я уверен, что вызов boost::bind с нулевым указателем (= создание объекта bind) следует считать неопределенным поведением, даже если падение произойдет только при его вызове.
.Я бы создал оберточный объект, чтобы сделать это. Что-то вроде следующего
#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 ) );
}
Скомпилируйте это и запустите его без аргументов и он установит mayBeNullFnPtr в NULL и вызовет do_stuff с классом-оберткой, и так распечатает 7. Запустите его с аргументом и он установит mayByNullFnPtr в aFunction и вызовет do_stuff с этим, распечатает 30.
Если вам нужно больше генерации, то вам понадобится шаблон класса-обертки DefaultingFromFnPtr, но это должно быть довольно легко сделать.
Вам придется взломать повышение.
Boost :: Bind возвращается Unspecified-N-N . Единственное, что справедливо связано с этими классами, является оператором (). Единственная вещь, которую вы знаете, состоит в том, что они копируют конструируемые и имеют Typedef для RESalvy_Type (который, кстати, означает, что вам не нужен шаблон для типа результата).
Вы хотите что-то еще - поэтому вам нужно найти определение Unspecified-Nn в Boost (там, возможно, несколько), взломать их, чтобы иметь функцию IS_NULL (), которая проверяет условия Вы хотите, а затем назовите это как ваш тест.
Это, конечно, при условии, что вы уверены, что вы всегда получите усиление :: Bind'Ed Object в вашей функции шаблона. Если кто-то пытается пройти регулярное указатель функции, он не скомпировался. Работая вокруг этого потребуется некоторая магия шаблона.