我不明白为什么未指定的lambda返回类型有时会工作,但不是所有时间都会工作,特别是在这段代码中。
template <typename T>
concept NoArgFunc =
requires (T f) {
f();
};
auto curry(NoArgFunc auto&& f) {
return f();
}
auto curry(auto&& f) {
return [=](auto&& ...x) {
return curry([=](auto&& ...xs) -> decltype(f(x..., xs...)) {
return f(x..., xs...);
});
};
}
int main() {
auto f = [](auto a, auto b, auto c, auto d, auto e) {
return a * b * c * d * e;
};
std::cout << curry(f)(1, 2)()(3)(4, 5);
}
这段代码在编译和输出时 120
然而,如果我不指定的是 decltype(f(x..., xs...))
的递归返回中的lambda。curry
函数,但它不能编译,并抱怨我给了2个参数而不是5个,这意味着咖喱化没有工作。为什么会这样?
我试图搜索并理解为什么这个返回类型规范是必要的,但没有成功。
下面是没有提供decltype时的完整错误信息。
main.cpp: In instantiation of ‘curry<main()::<lambda(auto:15, auto:16, auto:17, auto:18, auto:19)>&>::<lambda(auto:13&& ...)> [with auto:13 = {int, int}]::<lambda(auto:14&& ...)> [with auto:14 = {}]’:
main.cpp:31:6: required from ‘auto curry(auto:11&&) [with auto:11 = curry<main()::<lambda(auto:15, auto:16, auto:17, auto:18, auto:19)>&>::<lambda(auto:13&& ...)> [with auto:13 = {int, int}]::<lambda(auto:14&& ...)>]’
main.cpp:40:21: required from ‘curry<main()::<lambda(auto:15, auto:16, auto:17, auto:18, auto:19)>&>::<lambda(auto:13&& ...)> [with auto:13 = {int, int}]’
main.cpp:52:31: required from here
main.cpp:41:25: error: no match for call to ‘(const main()::<lambda(auto:15, auto:16, auto:17, auto:18, auto:19)>) (const int&, const int&)’
41 | return f(x..., xs...);
| ~^~~~~~~~~~~~~
main.cpp:48:14: note: candidate: ‘template<class auto:15, class auto:16, class auto:17, class auto:18, class auto:19> main()::<lambda(auto:15, auto:16, auto:17, auto:18, auto:19)>’
48 | auto f = [](auto a, auto b, auto c, auto d, auto e) {
| ^
main.cpp:48:14: note: template argument deduction/substitution failed:
main.cpp:41:25: note: candidate expects 5 arguments, 2 provided
41 | return f(x..., xs...);
| ~^~~~~~~~~~~~~
main.cpp: In instantiation of ‘curry<main()::<lambda(auto:15, auto:16, auto:17, auto:18, auto:19)>&>::<lambda(auto:13&& ...)> [with auto:13 = {int, int}]::<lambda(auto:14&& ...)> [with auto:14 = {const int&}]’:
main.cpp:41:25: recursively required from ‘curry<curry<main()::<lambda(auto:15, auto:16, auto:17, auto:18, auto:19)>&>::<lambda(auto:13&& ...)> [with auto:13 = {int, int}]::<lambda(auto:14&& ...)> >::<lambda(auto:13&& ...)> [with auto:13 = {}]::<lambda(auto:14&& ...)> [with auto:14 = {const int&}]’
main.cpp:41:25: required from ‘curry<curry<curry<main()::<lambda(auto:15, auto:16, auto:17, auto:18, auto:19)>&>::<lambda(auto:13&& ...)> [with auto:13 = {int, int}]::<lambda(auto:14&& ...)> >::<lambda(auto:13&& ...)> [with auto:13 = {}]::<lambda(auto:14&& ...)> >::<lambda(auto:13&& ...)> [with auto:13 = {int}]::<lambda(auto:14&& ...)> [with auto:14 = {}]’
main.cpp:31:6: required from ‘auto curry(auto:11&&) [with auto:11 = curry<curry<curry<main()::<lambda(auto:15, auto:16, auto:17, auto:18, auto:19)>&>::<lambda(auto:13&& ...)> [with auto:13 = {int, int}]::<lambda(auto:14&& ...)> >::<lambda(auto:13&& ...)> [with auto:13 = {}]::<lambda(auto:14&& ...)> >::<lambda(auto:13&& ...)> [with auto:13 = {int}]::<lambda(auto:14&& ...)>]’
main.cpp:40:21: required from ‘curry<curry<curry<main()::<lambda(auto:15, auto:16, auto:17, auto:18, auto:19)>&>::<lambda(auto:13&& ...)> [with auto:13 = {int, int}]::<lambda(auto:14&& ...)> >::<lambda(auto:13&& ...)> [with auto:13 = {}]::<lambda(auto:14&& ...)> >::<lambda(auto:13&& ...)> [with auto:13 = {int}]’
main.cpp:52:36: required from here
main.cpp:41:25: error: no match for call to ‘(const main()::<lambda(auto:15, auto:16, auto:17, auto:18, auto:19)>) (const int&, const int&, const int&)’
main.cpp:48:14: note: candidate: ‘template<class auto:15, class auto:16, class auto:17, class auto:18, class auto:19> main()::<lambda(auto:15, auto:16, auto:17, auto:18, auto:19)>’
48 | auto f = [](auto a, auto b, auto c, auto d, auto e) {
| ^
main.cpp:48:14: note: template argument deduction/substitution failed:
main.cpp:41:25: note: candidate expects 5 arguments, 3 provided
41 | return f(x..., xs...);
| ~^~~~~~~~~~~~~
➜ experiments g++10 -std=c++20 main.cpp
main.cpp: In instantiation of ‘curry<main()::<lambda(auto:15, auto:16, auto:17, auto:18, auto:19)>&>::<lambda(auto:13&& ...)> [with auto:13 = {int, int}]::<lambda(auto:14&& ...)> [with auto:14 = {}]’:
main.cpp:31:6: required from ‘auto curry(auto:11&&) [with auto:11 = curry<main()::<lambda(auto:15, auto:16, auto:17, auto:18, auto:19)>&>::<lambda(auto:13&& ...)> [with auto:13 = {int, int}]::<lambda(auto:14&& ...)>]’
main.cpp:40:21: required from ‘curry<main()::<lambda(auto:15, auto:16, auto:17, auto:18, auto:19)>&>::<lambda(auto:13&& ...)> [with auto:13 = {int, int}]’
main.cpp:52:31: required from here
main.cpp:41:25: error: no match for call to ‘(const main()::<lambda(auto:15, auto:16, auto:17, auto:18, auto:19)>) (const int&, const int&)’
41 | return f(x..., xs...);
| ~^~~~~~~~~~~~~
main.cpp:48:14: note: candidate: ‘template<class auto:15, class auto:16, class auto:17, class auto:18, class auto:19> main()::<lambda(auto:15, auto:16, auto:17, auto:18, auto:19)>’
48 | auto f = [](auto a, auto b, auto c, auto d, auto e) {
| ^
main.cpp:48:14: note: template argument deduction/substitution failed:
main.cpp:41:25: note: candidate expects 5 arguments, 2 provided
41 | return f(x..., xs...);
| ~^~~~~~~~~~~~~
main.cpp: In instantiation of ‘curry<main()::<lambda(auto:15, auto:16, auto:17, auto:18, auto:19)>&>::<lambda(auto:13&& ...)> [with auto:13 = {int, int}]::<lambda(auto:14&& ...)> [with auto:14 = {const int&}]’:
main.cpp:41:25: recursively required from ‘curry<curry<main()::<lambda(auto:15, auto:16, auto:17, auto:18, auto:19)>&>::<lambda(auto:13&& ...)> [with auto:13 = {int, int}]::<lambda(auto:14&& ...)> >::<lambda(auto:13&& ...)> [with auto:13 = {}]::<lambda(auto:14&& ...)> [with auto:14 = {const int&}]’
main.cpp:41:25: required from ‘curry<curry<curry<main()::<lambda(auto:15, auto:16, auto:17, auto:18, auto:19)>&>::<lambda(auto:13&& ...)> [with auto:13 = {int, int}]::<lambda(auto:14&& ...)> >::<lambda(auto:13&& ...)> [with auto:13 = {}]::<lambda(auto:14&& ...)> >::<lambda(auto:13&& ...)> [with auto:13 = {int}]::<lambda(auto:14&& ...)> [with auto:14 = {}]’
main.cpp:31:6: required from ‘auto curry(auto:11&&) [with auto:11 = curry<curry<curry<main()::<lambda(auto:15, auto:16, auto:17, auto:18, auto:19)>&>::<lambda(auto:13&& ...)> [with auto:13 = {int, int}]::<lambda(auto:14&& ...)> >::<lambda(auto:13&& ...)> [with auto:13 = {}]::<lambda(auto:14&& ...)> >::<lambda(auto:13&& ...)> [with auto:13 = {int}]::<lambda(auto:14&& ...)>]’
main.cpp:40:21: required from ‘curry<curry<curry<main()::<lambda(auto:15, auto:16, auto:17, auto:18, auto:19)>&>::<lambda(auto:13&& ...)> [with auto:13 = {int, int}]::<lambda(auto:14&& ...)> >::<lambda(auto:13&& ...)> [with auto:13 = {}]::<lambda(auto:14&& ...)> >::<lambda(auto:13&& ...)> [with auto:13 = {int}]’
main.cpp:52:36: required from here
main.cpp:41:25: error: no match for call to ‘(const main()::<lambda(auto:15, auto:16, auto:17, auto:18, auto:19)>) (const int&, const int&, const int&)’
main.cpp:48:14: note: candidate: ‘template<class auto:15, class auto:16, class auto:17, class auto:18, class auto:19> main()::<lambda(auto:15, auto:16, auto:17, auto:18, auto:19)>’
48 | auto f = [](auto a, auto b, auto c, auto d, auto e) {
| ^
main.cpp:48:14: note: template argument deduction/substitution failed:
main.cpp:41:25: note: candidate expects 5 arguments, 3 provided
41 | return f(x..., xs...);
| ~^~~~~~~~~~~~~
decltype
也作为SFINAE。
其他 [](auto&& ...xs){/**/}
是可以调用任何参数的,但可能会产生硬性错误。
那么,是否可以用 auto curry(NoArgFunc auto&& f)
.