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

问题描述

我尝试实现函数f:(std :: function-> int),该函数将1s传递到input_functor中 使用c ++可变参数模板。

让input_functor为g。

例如:

  • 如果g为std::function<int(int,int)>,则f返回g(1,1)
  • 如果g为std::function<int(int,int,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 ++)错误msg是它不能匹配候选对象。

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.

解决方法

您有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);
    }
    

Demo C ++ 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 */;