Water
Water

Reputation: 3655

invoke_result_t<> not matching lambda with a reference parameter

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

Answers (1)

Yakk - Adam Nevraumont
Yakk - Adam Nevraumont

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

Related Questions