Я не понимаю, почему неопределенные лямбда-возвращаемые типы иногда работают, но не всегда. В частности, в этом фрагменте кода:
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...))
для лямбда в рекурсивном возврате 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...);
| ~^~~~~~~~~~~~~