【问题标题】:Variadic Functions With Variadic Type Parameters具有可变类型参数的可变参数函数
【发布时间】:2017-07-19 23:01:43
【问题描述】:

我不确定我的尝试是否符合标准,甚至可能没有意义,所以请随时纠正我。

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

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

我试图做的是将传入的每个funcs 的返回值传递给另一个以扩展值形式接受它们的函数。例如。 std::make_shared&lt;TType&gt;(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;
}

已编辑以显示我原来问题的更好意图

【问题讨论】:

  • 你想做什么?
  • 如果编译器出现段错误,您可能需要提交错误报告。
  • 您是否希望传入CallFunctions 的每个函数都没有参数并返回一个值?
  • 同意,我将更新到最新版本以确保它仍然不受此错误的影响。如果是的话,我会提交报告。我还编辑了帖子中的代码以更好地显示意图,但@Yakk 的答案足够接近,足以让我得到我需要的东西。

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


【解决方案1】:
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())... );
}

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

【讨论】:

  • 这已经足够接近我需要的了,请编辑 c++17 示例以使用 funcs()... 语法调用函数,我会接受。我编辑了原始帖子以更清楚地解释我的意图。然后CallFunctions 函数的主体变为return std::make_shared&lt;TReturn&gt;(funcs()...);。当它被相应地编辑后,我会接受这个答案
  • @howard 我不认为funcs()...; 是有效的C++17;有什么改变吗?啊,我明白了,问题已编辑。
  • 我能收集到的最好的结果是,此语法已被参数包扩展覆盖:pattern .... 概述为here
  • decltype(std::make_shared&lt;R&gt;( 的东西 )) 不是 std::shared_ptr&lt;R&gt;,哪个更短更清晰?
  • 哦,我猜你想对 SFINAE 更友好。没关系。
【解决方案2】:

您可以使用 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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-09-23
    • 2023-03-08
    • 2012-12-19
    相关资源
    最近更新 更多