Reputation: 3655
Using a function that accepts templated functions works great when the type is either an rvalue reference or has no reference, but as soon as I make it an lvalue reference it breaks.
Note that V is currently unused here, but it still fails to compile anyways regardless of whether it's used or not.
using namespace std;
template <typename F, typename V = std::invoke_result_t<F, string>>
void func(F f) {
std::vector<string> v = { "a", "b", "c" };
std::for_each(v.begin(), v.end(), f);
}
int main() {
func([](string s) { return s.length(); }); // Good
// func([](string& s) { return s.length(); }); // Bad
func([](const string& s) { return s.length(); }); // Good
}
main.cpp: In function 'int main()':
main.cpp:18:46: error: no matching function for call to 'func(main()::)'
func([](string& s) { return s.length(); }); ^
main.cpp:11:6: note: candidate: 'template void func(F)'
void func(F f) { ^~~~
main.cpp:11:6: note: template argument deduction/substitution failed:
I can't do something like
std::invoke_result_t<F, string&>
and I couldn't do something like
std::invoke_result_t<F, std::add_lvalue_reference_t<string>>
The last one was a shot in the dark. My template knowledge is not that great. I've been searching around on here and on various blogs/google/etc, haven't had much success.
Upvotes: 0
Views: 577
Reputation: 275435
std::invoke_result_t<F, string>
this means passing F
a string
rvalue. And you cannot if F
takes an lvalue reference.
I can't do something like
std::invoke_result_t<F, string&>
well yes you can. Do that if you want to know what the result of calling it with a non-const lvalue is.
At your point of use in your sample code, you pass it an lvalue. The string&&
overload does not work.
Upvotes: 2