boost::bind 与空函数指针

发布于 2024-08-16 12:18:51 字数 854 浏览 9 评论 0原文

如果嵌入在 boost::bind 返回对象中的函数指针是 NULL/nullptr/0,我需要采取除调用之外的操作。如何确定对象是否包含空函数指针?

附录

  1. 我不相信我可以使用和比较 boost::function ,因为 boost::bind 返回对象与模板函数中的不同调用签名一起使用。
  2. 简化示例:
模板 
Retval do_stuff(BRO func, enum Fallback 后备)
{
    if (func == NULL)
    {
        返回 do_fallback(后备);
    }
    别的
    {
        返回 use_retval(func());
    }
}

do_stuff(boost::bind(FuncPtrThatMightBeNull, var1, var2), 回退);

解决方案

由于被调用者中函数的数量没有改变,我可以将绑定返回对象“转换”为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());
}

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

屋顶上的小猫咪 2024-08-23 12:18:51

您可以绑定到虚拟函数:

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

...或者,假设您将 Boost.BindBoost.Function 一起使用,返回默认构造的函数对象并检查对于 empty()< /code>在调用之前:

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

如果您想将该处理移出调用代码,您可以模拟可变参数模板函数以支持变量参数:

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

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

小情绪 2024-08-23 12:18:51

我会创建一个包装对象来执行此操作。类似下面的内容

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

编译它并在不带参数的情况下运行它,它将 mightBeNullFnPtr 设置为 NULL 并使用包装类调用 do_stuff ,因此打印出 7。使用参数运行它,它将设置 mightByNullFnPtr 为 aFunction 并使用它调用 do_stuff ,打印出 30。

如果您想要更多的通用性,您将需要模板化 DefaultingFromFnPtr 包装类,但这应该很容易做到。

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.

你怎么敢 2024-08-23 12:18:51

我非常确定使用空指针调用 boost::bind (= 绑定对象的创建)应该被视为未定义的行为,即使崩溃仅在调用它时发生。

I'm pretty sure calling boost::bind with a null pointer (= the creation of the bind object) should be considered undefined behavior, even if the crash only happens when calling it.

墨小墨 2024-08-23 12:18:51

你将不得不破解提升。

boost::bind 返回unspecified-nn。对这些类唯一有效的操作是operator()。您唯一知道的另一件事是它们是可复制构造的,并且有一个 result_type 的 typedef (顺便说一句,这意味着您不需要结果类型的模板)。

你想要别的东西 - 所以你需要在 boost 中找到 unspecified-nn 的定义(可能有几个),修改它们以获得一个 is_null() 成员函数来检查你想要的条件,然后将其称为您的测试。

当然,这是假设您确定您将始终在模板函数中获得 boost::bind'ed 对象。如果有人尝试传入常规函数指针,它将无法编译。解决这个问题需要一些模板魔法。

You're going to have to hack boost.

boost::bind returns unspecified-n-n. The only thing valid to do with these classes is operator(). The only other thing you know is that they are copy constructable, and have a typedef for result_type (which, by the way, means you don't need a template for result type).

You want something else - so you'll need to find the definition of unspecified-n-n in boost (there maybe several), hack them to have a is_null() member function which checks for the conditions you want, then call that as your test.

This is, of course, assuming you are certain you'll always get a boost::bind'ed object in your template function. If someone tries passing in a regular function pointer, it won't compile. Working around this will require some template magic.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文