I'm trying to use std::invoke_result_t
and it fails when called for nested lambda in function with auto
return type. Here is a reproducer:
template <typename T, typename... Args>
auto print_ret_type(T &&t, Args &&... args) {
using ret_type = std::invoke_result_t<T, Args...>;
std::cout << typeid(ret_type).name() << std::endl;
}
int main(int argc, const char **argv) {
auto worker = [](int i) {
auto worker_impl = [](int i, auto &worker) {
print_ret_type(worker, i, worker);
};
worker_impl(i, worker_impl);
};
worker(10);
return 0;
}
I get the following error:
include/c++/9.3.0/type_traits:2783:5: error: no type named 'type' in 'std::invoke_result<(lambda at test.cpp:13:24) &, int &, (lambda at test.cpp:13:24) &>'
using invoke_result_t = typename invoke_result<_Fn, _Args...>::type;
If I use void
return type for print_ret_type
instead of auto
the test compiles successfully. There is a returned template structure in my original code, which depends on ret_type
. Can anyone explain why I get an error when auto
return type is used?
The rules for how return type deduction work are a bit quirky.
To determine the return type, it actually instantiates the body of the function. Any errors in this instantiation are hard errors.
Lambdas return types are implicitly ->auto
basically; so those rules apply to them. If you want to know the return type of worker
, every line of worker must be instantiated , and ditto for worker_impl
.
auto worker = [](int i) {
auto worker_impl = [](int i, auto &worker) {
print_ret_type(worker, i, worker);
};
worker_impl(i, worker_impl); // << worker_impl has no return type yet
};
worker(10);
The return type is demanded in:
template <typename T, typename... Args>
auto print_ret_type(T &&t, Args &&... args) {
using ret_type = std::invoke_result_t<T, Args...>;
this function is instantiated inside worker_impl
to determine its return type in order to determine the return type of worker_impl
.
Change it to add ->void
to worker_impl
:
auto worker_impl = [](int i, auto &worker)->void {
and it compiles, or print_ret_type
to return void
.
Either one blocks the instantiation of the invoke result at a point where we don't know the return type of worker_impl
yet.
Naively, the simple rule "no return
statement, an auto
return body returns void
" would be what you'd think is used. But C++ doesn't have that rule.
Return type deduction does not untangle all possible cases. Sometimes you have to make the return type explicit.
And the rules for what happens when deducing return type are not as narrow as they could be. While the return type of print_ret_type
does not matter to the return type of worker_impl
, the standard (out of generosity to compiler implementors) gets them to do something closer to "real compilation" there.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.