1

Here's the snippet that I am trying to make it work

#include <functional>
#include <stdio.h>
#include <utility>

void
bar(std::function<void(int* a)>&& aFunction)
{}

void
foo(std::function<void(int* a)>&& aFunction)
{
  bar(std::forward(aFunction));
}

int
main()
{
  int b = 123;
  foo([b](int*) { printf("Calling \n"); });
  return 0;
}

Compiling with clang++ gives me

➜  /tmp clang++ main.cpp -g -o main
main.cpp:12:7: error: no matching function for call to 'forward'
  bar(std::forward(aFunction));
      ^~~~~~~~~~~~
/usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/10.2.0/../../../../include/c++/10.2.0/bits/move.h:76:5: note: candidate template ignored: couldn't infer template argument '_Tp'
    forward(typename std::remove_reference<_Tp>::type& __t) noexcept
    ^
/usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/10.2.0/../../../../include/c++/10.2.0/bits/move.h:87:5: note: candidate template ignored: couldn't infer template argument '_Tp'
    forward(typename std::remove_reference<_Tp>::type&& __t) noexcept
    ^
1 error generated.

I don't know if this is related to the capture clause actually. How can I make the code snippet work?

Shuo Feng
  • 445
  • 7
  • 13
  • 3
    use std::move instead of std::forward to make it work – 0RR Dec 14 '20 at 18:49
  • 2
    `foo` isn't a template function, so its argument is not [a universal/forwarding reference](https://en.cppreference.com/w/cpp/language/reference#Forwarding_references), just a plain r-value reference; `std::forward` is for universal/forwarding references; it doesn't apply here. – ShadowRanger Dec 14 '20 at 18:51
  • This has nothing to do with perfect forwarding, which is all about preserving unknown reference type. You don't need `std::forward` here at all. – n. m. could be an AI Dec 14 '20 at 18:51
  • 2
    `std::forward` disables template argument deduction. You need to provide its template argument explicitly. See, e.g, https://stackoverflow.com/a/27501467/580083. – Daniel Langr Dec 14 '20 at 18:52
  • 1
    You can _perfectly forward_ that lambda, or you can use `std::function` to facilitate a type-erased parameter. **But you can't do both**. And it seems that you are asking how to do both. Do you want your code snipped to be (minimally) fixed, or to forward the lambda as a parameter? – Drew Dormann Dec 14 '20 at 19:00

1 Answers1

5

This is not a use case for std::forward in the first place; foo's aFunction is not a universal/forwarding reference, so std::forward doesn't apply.

You just want to unconditionally move the r-value reference to pass it along to bar; changing the code to:

bar(std::move(aFunction));

is sufficient to make that work.

ShadowRanger
  • 143,180
  • 12
  • 188
  • 271
  • 2
    I would also add that even if it was a universal reference, that code would still not work (not even by resolving to a no-op), for the simple reason that `std::forward` _requires_ an explicit template argument, because it disables argument type deduction. – Enlico Dec 14 '20 at 19:04
  • 2
    @Enlico: Sure. I'm not adding it to the answer because, with no template involved, making `std::forward` make sense is weird (you basically always use it with a template type, e.g. `std::forward`, we have no `T` to use that wouldn't look insane), but it's good for the OP to know. – ShadowRanger Dec 14 '20 at 19:12