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