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

How to do variadic deduction in std::function's parameters?

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

设input_functor为g.

例如:

#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.

您有 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 */;