简体   繁体   English

传递可变参数函数作为参数

[英]Passing a variadic function as argument

Consider this working code: 考虑以下工作代码:

#include <iostream>
#include <utility>
#include <array>

template <typename... Args>
void foo (Args&&... args) {
    const auto v = {args...};
    for (auto x : v) std::cout << x << ' ';     std::cout << '\n';
}

template <typename> struct Foo;

template <std::size_t... Is>
struct Foo<std::index_sequence<Is...>> {
    template <typename Container>
    static void execute (const Container& v) {
        foo(v[Is]...);
    }
};

template <std::size_t N>
void fooArray (const std::array<int, N>& a) {
    Foo<std::make_index_sequence<N>>::execute(a);
}

int main() {
    fooArray<6>({0,1,2,3,4,5});  // 0 1 2 3 4 5
}

I want to now generalize the Foo struct like so: 我现在想像这样概括Foo结构:

#include <iostream>
#include <utility>
#include <array>

template <typename... Args>
void foo (Args&&... args) {
    const auto v = {args...};
    for (auto x : v) std::cout << x << ' ';     std::cout << '\n';
}

template <typename> struct Foo;

template <std::size_t... Is>
struct Foo<std::index_sequence<Is...>> {
    template <typename Container, typename F>  // *** Modified
    static void execute (const Container& v, F f) {
        f(v[Is]...);
    }
};

template <std::size_t N>
void fooArray (const std::array<int, N>& a) {
    Foo<std::make_index_sequence<N>>::execute(a, foo);
}

int main() {
    fooArray<6>({0,1,2,3,4,5});
}

But I get a compile error (from GCC 4.9.2) that F cannot be deduced. 但是我收到了一个编译错误(来自GCC 4.9.2),无法推导出F。 How do I achieve this? 我该如何实现?

foo is a family of overloads, and so the foo is ambiguous. foo是重载族,因此foo是模棱两可的。
(even foo<int, int> is, as it may have additional type too). (即使foo<int, int>也是如此,因为它也可能具有其他类型)。

You may force expected type function as follow: 您可以如下强制使用预期的类型函数:

template <std::size_t... Is>
struct Foo<std::index_sequence<Is...>> {
    template <typename Container>
    static void execute (const Container& v, void (*f)(decltype(v[Is])&...)) {
        f(v[Is]...);
    }
};

Live example 现场例子

An alternative is to wrap function foo into a class: 另一种方法是将函数foo包装到一个类中:

class FooCaller
{
public:
    template <typename... Args>
    void operator () (Args&&... args) const {
        const auto v = {args...};
        for (auto x : v) std::cout << x << ' ';     std::cout << '\n';
    }

};

and keep your implementation: 并保持您的实施:

Live Demo 现场演示

A template is not a single thing. 模板不是一回事。 You cannot pass a template function as a function or an object. 您不能将模板函数作为函数或对象传递。 Now the name of an overload set (say, foo ) can resolve to a single instance of a template function in particular contexts (where you call it, or convert it to a function pointer), which is probably what fooled you. 现在,重载集的名称(例如foo )可以在特定上下文(在其中调用它或将其转换为函数指针)中解析为模板函数的单个实例,这很可能是骗了您的。

If you want to work with an entire overload set as an object, you can approximate it via: 如果要使用整个过载集作为对象,则可以通过以下方式对其进行近似:

struct foo_f{
  template<class...Args>
  auto operator()(Args&&...args)const->
  decltype(foo(std::declval<Args>()...))
  { return foo(std::forward<Args>(args)...); }
};

and now an instance of foo_f approximates the overload set of foo as a single object. 现在foo_f的实例将foo的重载集近似为单个对象。 Pass foo_f{} in place of foo . 传递foo_f{}代替foo

In C++14, alternatively: 在C ++ 14中,也可以:

[](auto&&...args)->decltype(auto){return foo(decltype(args)(args)...);}

is a lambda that behaves much like foo_f above. 是一个lambda,其行为与上面的foo_f非常相似。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM