【问题标题】:Passing function pointer arguments with boost使用 boost 传递函数指针参数
【发布时间】:2013-03-10 14:28:02
【问题描述】:

是否可以使用 boost::function 和/或 boost::bind 来简化/改进以下函数指针传递?

void PassPtr(int (*pt2Func)(float, std::string, std::string))
{
   int result = (*pt2Func)(12, "a", "b"); // call using function pointer
   cout << result << endl;
}

// execute example code
void Pass_A_Function_Pointer()
{
   PassPtr(&DoIt);
}

【问题讨论】:

  • 这取决于您要寻找什么样的答案!当然,以上所有内容都可以简化为cout &lt;&lt; DoIt(12, "a", "b") &lt;&lt; endl;,但我想这不是你要找的。也就是说,这里没有明显的机会利用 Boost 功能,因为您调用的是纯函数指针,而不是函数对象等。
  • 可以改进的地方在于您可以使用任何成员函数或 lambdas(如果您有 C++11 兼容的编译器),而不仅仅是普通函数或静态成员函数。当然,使用boost::bind(或std::bind),您可以在传递函数对象之前“绑定”任意数量的参数。
  • 什么是固定的,什么可以改变?如果PassPtrDoIt 的签名是固定的,那么没有,代码就这么简单。
  • @Charles - 解决的所有问题是我希望传递一个指向函数的指针,例如 DoIt,然后调用它。其他一切都可以改变。
  • 如果你想传递一个指向函数的指针,那么你应该以最简单的方式来做。

标签: c++ boost boost-bind boost-function


【解决方案1】:

您可以使用boost::function&lt;&gt; 使使用不同类型的可调用对象作为函数的输入成为可能。

下面是一个使用 C++11 的例子(见这个例子后面的备注)。这就是你重写函数的方式:

#include <functional>
#include <string>
#include <iostream>

void PassFxn(std::function<int(float, std::string, std::string)> func)
//           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
{
   int result = func(12, "a", "b"); // call using function object
   std::cout << result << std::endl;
}

以下是几个测试它的函数:

int DoIt(float f, std::string s1, std::string s2)
{
    std::cout << f << ", " << s1 << ", " << s2 << std::endl;
    return 0;
}

int DoItWithFourArgs(float f, std::string s1, std::string s2, bool b)
{
    std::cout << f << ", " << s1 << ", " << s2 << ", " << b << std::endl;
    return 0;
}

struct X
{
    int MemberDoIt(float f, std::string s1, std::string s2)
    {
        std::cout << "Member: " << f << ", " << s1 << ", " << s2 << std::endl;
        return 0;
    }

    static int StaticMemberDoIt(float f, std::string s1, std::string s2)
    {
        std::cout << "Static: " << f << ", " << s1 << ", " << s2 << std::endl;
        return 0;
    }
};

这是测试例程:

int main()
{
    PassFxn(DoIt); // Pass a function pointer...

    // But we're not limited to function pointers with std::function<>...

    auto lambda = [] (float, std::string, std::string) -> int
    {
        std::cout << "Hiho!" << std::endl;
        return 42;
    };

    PassFxn(lambda); // Pass a lambda...

    using namespace std::placeholders;
    PassFxn(std::bind(DoItWithFourArgs, _1, _2, _3, true)); // Pass bound fxn

    X x;
    PassFxn(std::bind(&X::MemberDoIt, x, _1, _2, _3)); // Use a member function!

    // Or, if you have a *static* member function...
    PassFxn(&X::StaticMemberDoIt);

    // ...and you can basically pass any callable object!
}

这是live example

备注

如果您正在使用 C++03,您可以轻松地将 std::function&lt;&gt; 更改为 boost::function&lt;&gt; 并将 std::bind&lt;&gt; 更改为 boost::bind&lt;&gt;(事实上,Boost.Function 是启发 std::function&lt;&gt; 并后来成为标准 C++ 库)。在这种情况下,您必须包含 boost/function.hppboost/bind.hpp 标头,而不是包含 &lt;functional&gt; 标头(后者仅在您想使用 boost::bind 时才包含)。

有关进一步的示例,应该让您感受到std::function&lt;&gt; / boost::function&lt;&gt; 通过封装任何类型的可调用对象的能力为您提供的强大功能,另请参阅this Q&A on StackOverflow

【讨论】:

  • 太好了!在我标记为已回答之前,您能否再添加一个示例。当 DoIt 是被传递的成员函数时,语法将如何查找?
  • @pingu:很高兴它有帮助。如果您想看一下,我还更新了实时示例。
【解决方案2】:

我假设您想改进PassPtr 的功能,而不是您提供的所有示例代码。如果您使用的是 C++11 并且可以使用 lambda 表达式,我会将其简化为:

template <typename Func>
void PassPtr(Func f) {
  std::cout << f(12, "a", "b") << std::endl;
}

这将允许任何可调用对象作为f 传递。通过推导模板类型获取函数的原因是允许内联传递的任何 lambda。当然,这不会对传递的函数强制执行任何特定签名(或者它甚至应该是可调用对象)。例如,如果你传递一个int,你会得到一些令人困惑的编译器错误。

使用[boost|std]::function 的替代方法是这样做:

void PassPtr(std::function<int(float, std::string, std::string)> f) {
  std::cout << f(12, "a", "b") << std::endl;
}

这将允许传递任何类型的可调用对象,就像上面一样,但可能不会导致 lambda 被内联。

【讨论】:

    猜你喜欢
    • 2012-05-03
    • 2016-11-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-02-13
    • 2018-08-25
    相关资源
    最近更新 更多