I want to write a function foo
that should call operator()
of its parameter, as illustrated in the (broken) code below:
template <typename T> void foo(const T& x){
x();
}
struct MyFunctor{
int data;
void operator()(){
/* stuff that might modify the data */
}
};
int main()
{
foo(MyFunctor{});
}
Obviously the code doesn't work, because operator()
is non-const
, but foo()
requires its parameter to be const
.
As a template function, foo()
should work with both const
and non-const
functors, and not be picky about the const
-ness of its argument.
If I change foo()
by removing the const
to the following:
template <typename T> void foo(T& x) { /* ... */ }
... it also won't work because you can't convert an rvalue reference to a non-const
lvalue reference, so foo(MyFunctor{})
cannot be called.
Changing foo()
to a forwarding reference resolves all the problems:
template <typename T> void foo(T&& x) { /* ... */ }
But is this the "right" way? Shouldn't forwarding references be used only with std::forward()
(i.e. the parameter shouldn't be touched apart from forwarding it to another function)?
Yes, a forwarding reference is the right way, and if it calms you, you can certainly forward the parameter:
template <typename T> void foo(T&& x){
std::forward<T>(x)();
}
Now it even works with ref-qualified call operators.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With