如何在 std::function 的参数中进行可变推导?
How to do variadic deduction in std::function's parameters?
我尝试实现一个函数 f: (std::function -> int) 它将把 1 传递给 input_functor
使用 C++ 可变参数模板。
设input_functor为g.
例如:
- 如果g是
std::function<int(int,int)>
,那么freturng(1, 1)
.
- 如果g是
std::function<int(int,int,int)>
,那么freturng(1, 1, 1)
.
- 如果g是
std::function<int(int,int,int,int)>
,那么freturng(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.
您有 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 */;
我尝试实现一个函数 f: (std::function -> int) 它将把 1 传递给 input_functor
使用 C++ 可变参数模板。
设input_functor为g.
例如:
- 如果g是
std::function<int(int,int)>
,那么freturng(1, 1)
. - 如果g是
std::function<int(int,int,int)>
,那么freturng(1, 1, 1)
. - 如果g是
std::function<int(int,int,int,int)>
,那么freturng(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.
您有 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 */;