使用可变数量的参数存储 boost::function 对象

Storing boost::function object with variable number of arguments

我想要实现的是创建一个存储任何类型方法的结构。我稍后可以调用 struct_object.run() 来 运行 我存储的方法。

此方法可以return任何类型的值,最重要的是,可以使用任意数量的参数;但是,我无法解决 "any amount of parameters" 问题。

请注意,以下代码甚至无法构建,主要是因为我不知道正确的语法是什么样的。

ApplicationPair.h

template<typename T, typename... Args>
struct ApplicationPair
{
    ApplicationPair(boost::function<T()> func, Args... arguments )
    {
        _func = func(Args::arguments...);
    }

    ApplicationPair() = delete;

    void run(); 
    boost::function<T(Args...)> _func;
};

#endif

然后,我想做的是:

main.cpp

template<typename T, typename... Args>
void ApplicationPair<T,Args...>::run()
{
    this->_func;
}

//TEST

int counter = 0;

void HelloWorld()
{
    std::cout << "HelloWorld\n";
}

void printNumber(int i)
{
    std::cout << "Print: " << i << std::endl;
}

void increaseCounter(int x)
{
   counter+=x;
}

int main()
{
    ApplicationPair<void> p1(HelloWorld);
    ApplicationPair<void> p2(printNumber, 5);
    ApplicationPair<void> p3(increaseCounter, 10);
    p1.run();
    p2.run();
    p3.run();
    return 0;
}

基本上,我想要存储的方法不应该以任何方式修改或改编:我希望能够创建任何类型的方法而不用关心 struct ApplicationPair 会为自己的个人存储它这一事实使用。

尽管如此,我得到的只是一长串错误,例如:

error: in declaration ‘typename boost::enable_if_c<(! boost::is_integral::value), boost::function&>::type boost::function::operator=(Functor)’

在下一行中:

ApplicationPair<void> p2(printNumber, 5);

你必须在模板参数列表中指定所有类型,不仅 void 作为 return 类型,还应添加 int 作为构造函数的参数。现在 args... 是空的。怎么了。与 p3.

相同

将构造函数作为模板化方法,将参数包作为可调用对象的参数:

template<class F, class ... Args>
ApplicationPair(F&& func, Args... arguments )
{
    _func = boost::bind(std::forward<F>(func),arguments...);
}

则在调用构造函数时可以推导出args...。您的 class 模板仅采用 return 值的类型。

template<class Ret>
struct ApplicationPair {
    template<class F, class ... Args>
    ApplicationPair(F&& func, Args... arguments )
    {
        _func = boost::bind(std::forward<F>(func),arguments...);
    }
    ApplicationPair() = delete;
    void run() {
        this->_func();
    }
    boost::function<Ret()> _func;
};

在构造函数中boost::bind用于将传递的参数绑定到可调用的。您不会在任何地方存储参数,因此它们必须绑定在由 boost::bind.

创建的函子中

使用:

ApplicationPair<void> p1(HelloWorld);
ApplicationPair<void> p2(printNumber, 5);
ApplicationPair<void> p3(increaseCounter, 10);

Demo


不要使用 boost::bind,它最多只能处理 9 个参数。

你已经得到了答案,但这里有一个 C++17 替代方案,能够使用推导指南推导 return 值类型以及函数的参数类型,从而使 return 类型和参数类型是 ApplicationPair<> 类型的一部分。我选择将参数单独存储在 std::tuple<Args...>.

中 在此示例中,

boost::function 可以替换为 std::function,以防您以后决定使用标准:

#include <boost/function.hpp>
#include <iostream>
#include <type_traits>
#include <tuple>

template<typename T, typename... Args>
struct ApplicationPair {
    ApplicationPair() = delete;

    ApplicationPair(Func func, Args... args) : 
        _func(func),
        // store the arguments for later use
        arguments(std::make_tuple(std::forward<Args>(args)...))
    {}

    decltype(auto) run() {        // I'd rename this: decltype(auto) operator()()
        return std::apply(_func, arguments);
    }

    boost::function<T(Args...)> _func;
    std::tuple<Args...> arguments;
};

// deduction guide
template<typename Func, typename... Args>
ApplicationPair(Func, Args...) -> 
    ApplicationPair<std::invoke_result_t<Func, Args...>, Args...>;
int counter = 0;

void HelloWorld()
{
    std::cout << "HelloWorld\n";
}

void printNumber(int i)
{
    std::cout << "Print: " << i << std::endl;
}

int increaseCounter(int x) // changed return type for demo
{
   counter+=x;
   return counter;
}

int main()
{
    // full deduction using the deduction guide
    ApplicationPair p1(HelloWorld);
    ApplicationPair p2(printNumber, 5);
    ApplicationPair p3(increaseCounter, 10);
    p1.run();
    p2.run();
    std::cout << p3.run() << '\n';
    std::cout << p3.run() << '\n';
}