I'm curious if, in general, you are to use T&& (universal reference) instead of the classic T const& (l-value reference) for templated function parameters starting with C++11. What I'm especially curious is how you get around the fact that you are forced to lose the const if you want to also handle r-value references; is there a way around this?
The const keyword allows you to specify whether or not a variable is modifiable. You can use const to prevent modifications to variables and const pointers and const references prevent changing the data pointed to (or referenced).
Yes, you should use const whenever possible. It makes a contract that your code will not change something. Remember, a non-const variable can be passed in to a function that accepts a const parameter.
The compiler will issue an error if an attempt is made to change a value using a const qualified pointer, but declaring such a pointer will not change the generated code.
We use the const qualifier to declare a variable as constant. That means that we cannot change the value once the variable has been initialized. Using const has a very big benefit. For example, if you have a constant value of the value of PI, you wouldn't like any part of the program to modify that value.
There is no problem with "losing the const". T
will be deduced with cv-qualifiers if the argument is cv-qualified. For example, if the argument is an rvalue of type const std::string
, then T
will be deduced as const std::string
. You cannot possibly violate const-correctness by using forwarding references. If you could, it would be a major language defect.
As for the broader question of when forwarding references should be used, see here: Proper use of universal references
You are not forced to lose const:
template<typename T> void fun(T &&val)
might bind non-const lvalues, const l-values and rvalues. You are still perfectly allowed to do template<typename T> void fun(const T &v)
which will be a more specialized overload for const references, hence non-modifiable l-values will hit this overload.
The first overload, with the 'forward reference' will bind to modifiable values and rvalues. If I read a prototype of a template function with a forwarding reference (what S. Meyers baptized as "universal reference") what that tells me is that the function might take advantage of move semantics, nothing more.
It is possible to detect the constness of the argument internally; however, since you ask whether this is the recommended general way, I would say that managing the non-modifiable l-value in its own overload is recommended except when impractical (such as when dealing with multiple parameters that may or not be const)
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