如何在 std::function 的参数中进行可变参数推导?

Posted

技术标签:

【中文标题】如何在 std::function 的参数中进行可变参数推导?【英文标题】:How to do variadic deduction in std::function's parameters? 【发布时间】:2020-09-21 16:22:07 【问题描述】:

我尝试实现一个函数 f: (std::function -> int) 它将 1 传递给 input_functor 使用 c++ 可变参数模板。

令 input_functor 为 g。

例如:

如果g是std::function<int(int,int)>,那么f返回g(1, 1)。 如果g是std::function<int(int,int,int)>,那么f返回g(1, 1, 1)。 如果g是std::function<int(int,int,int,int)>,那么f返回g(1, 1, 1, 1)
#include <functional>
#include <iostream>

template <typename T, typename... Args>
int apply(std::function<int(T, Args...)> func) 
    auto tmp = [func](Args... args) 
        return func(1, args...);
    ;
    return apply(tmp);


template <typename T>
int apply(std::function<int(T)> func) 
    return func(1);


int main() 
    std::function<int(int, int)> f = [](int a, int b) 
        return a + b;
    ;
    std::cout << apply(f) << "\n";
    return 0;

编译器 (clang++) 错误消息是它无法匹配候选。

main.cpp:9:12: error: no matching function for call to 'apply'
    return apply(tmp);
           ^~~~~
main.cpp:21:18: note: in instantiation of function template specialization 'apply<int, int>' requested here
    std::cout << apply(f) << "\n";
                 ^
main.cpp:5:5: note: candidate template ignored: could not match 'function<int (type-parameter-0-0, type-parameter-0-1...)>' against
      '(lambda at main.cpp:6:16)'
int apply(std::function<int(T, Args...)> func) 
    ^
main.cpp:13:5: note: candidate template ignored: could not match 'function<int (type-parameter-0-0)>' against '(lambda at main.cpp:6:16)'
int apply(std::function<int(T)> func) 
    ^
1 error generated.

【问题讨论】:

您可能需要显式指定tmp 的类型,您不能从lambda 中推断出std::function 模板参数。或者,显式指定对apply的递归调用的类型可能更简单 不确定编译器是否能够优化掉所有的 std::functions,代码可能有点慢 【参考方案1】:

您有 2 个问题:

定义顺序:

template <typename T>
int apply(std::function<int(T)> func) 
    return func(1);

应该放在递归函数之前,以便可见并结束递归。

lambda 不是std::function,所以不会发生推断

template <typename T, typename... Args>
int apply(std::function<int(T, Args...)> func) 
    auto tmp = std::function[func](Args... args)  // C++17 CTAD
        return func(1, args...);
    ;
    return apply(tmp);

DemoC++17

由于您仅限于 C++11,因此您可以创建特征来了解需要哪个 std::function

template <typenate T, typename Discarded>
struct always_first

    using type = T;
;
template <typenate T, typename Discarded> using always_first_t = typename always_first<T, Discarded>::type;

// possibly directly
// template <typenate T, typename Discarded> using always_first_t = T;
// but old compilers might have some issues with that construct as std::void_t

然后

std::function<int(always_first_t<int, Args>...)> tmp = /* your lambda */;

【讨论】:

以上是关于如何在 std::function 的参数中进行可变参数推导?的主要内容,如果未能解决你的问题,请参考以下文章

Cython:具有自定义参数类型的 std::function 回调

C++ std::function 参数 const 参考

如何返回使用参数包定义的成员函数的 std::function 对象?

如何将 std::function 包装器转换为可变参数函数?

从std :: function中推导返回和参数类型作为模板函数参数传递?

模板函数替换仅在一个参数中未使用std :: function时才起作用