具有可变参数类型的变量函数

时间:2017-07-19 23:01:44

标签: c++ variadic-templates c++17 variadic-functions

我不确定标准是否允许我尝试的是什么,甚至可能没有意义,所以请务必随时纠正我。

我正在尝试将可变数量的std::function对象传递给接受可变参数的函数,并且还接受可变参数模板参数。模板参数指定传入函数的返回类型。函数的签名如下所示:

template <typename ... TRets>
void DoStuff(std::function<TRets...()> funcs...)

我尝试做的是将传入的funcs中的每一个的返回值传递给另一个以扩展值形式接受它们的函数。例如。 std::make_shared<TType>(funcs()...);

我正在使用带有--std=c++17标志的g ++ 7.1.1,这会导致编译器出错。显然它不应该是错误的,但是标准中有什么说上面的代码是无效的吗?或许,是否有不同的语法来实现这一目标?

为了完整性,这里是一个最小的工作(对于一些工作的定义)例子:

#include <functional>
#include <memory>

class MyClass {
    public:
        int m_a;
        double m_b;
        MyClass(int a, double b) : m_a(a), m_b(b) {};
};


template <typename TReturn, typename ... Args>
std::shared_ptr<TReturn> CallFunctions(std::function<Args...()> funcs...) {
    // Do stuff here
    return std::make_shared<TReturn>(funcs()...);
}

int main(int argc, char * argv[]) {
    auto x = CallFunctions<MyClass, int, double>(
        [] () { return 5; },
        [] () { return 3.14; }
    );

    return 0;
}

编辑以显示原始问题的更好意图

2 个答案:

答案 0 :(得分:3)

template <class R, class... Args>
std::shared_ptr<R> CallFunctions(std::function<Args()>... funcs) {
  return std::make_shared<R>( funcs()... );
}

这是C ++ 11。这是低效的。

template <class R, class... Args>
auto CallFunctions(Args&&... funcs) 
-> decltype(std::make_shared<R>( funcs()... ))
{
  return std::make_shared<R>( funcs()... );
}

删除了不必要的类型擦除,需要明确地传递返回类型。

如果你真的想传递返回类型:

template <class R, class... Args, class...Fs>
auto CallFunctions(Fs&&... funcs) 
-> decltype(std::make_shared<R>( static_cast<Args>(funcs())... ))
{
  return std::make_shared<R>( static_cast<Args>(funcs())... );
}

但我建议做上面的第二个解决方案。

答案 1 :(得分:0)

您可以使用C ++ 17 std::apply在参数包的每个元素上使用std::invoke。那么你不再需要std::function了,因为std::invoke只能调用可调用的对象,而且你不必再提供显式的模板参数(无论如何都是反模式)。作为奖励,您甚至可以检索被调用函数的返回值。

#include <functional>
#include <iostream>
#include <memory>
#include <tuple>

template < typename... R, typename... Args >
auto CallFunctions(Args... funcs) {
    // Do stuff here
  return std::apply(
    [] (auto&&... x) {
      return std::make_tuple(std::make_shared<R>(std::invoke(x))...);
    }, std::make_tuple(funcs...)
    );
}

int main() {
    auto r = CallFunctions<int,double>(
        [] () { return 5; },
        [] () { return 3.14; }
    );

    std::cout << *std::get<0>(r) << ' ' << *std::get<1>(r) << '\n';

    return 0;
}

Live example