From Item 23:
-
std::move
cast a value (no matter what kind of value it is) to a rvalue. An approximate implementation is:
//C++ 14
template<typename T>
decltype(auto) move(T&& param)
//C++ 11
template<typename T>
typename remove_reference<T>::type&&
{
using ReturnType = remove_reference_t(T)&&;
return static_cast<ReturnType>(param);
}
If you want to move anything, don't declare it to be
const
. Think about how string and vector are moved.Fill in the gap here on how
std::forward
actually works, but conceptually it is just a cast as well, a conditional cast.
From Item 24:
- Two examples of
universal/forwarding references
:
template<typename T>
void f(T&& param); // param is universal reference
auto&& var2 = var1; // var2 is universal reference
Universal references come from type deduction (see examples above).
Why do we need to know this? --> Not sure at this moment.
From Item 25:
Use std::move on rvalue references and std::forward on universal references
The first take away for me here, which seems a bit surprising still, is this example:
class Widget {
public:
Widget(Widget&& rhs)
: name (std::move(rhs.name)),
p(std::move(rhs.p)
{ ... }
...
}
So why do we need std::move
for rhs.name
? That is because rhs
is actually a lvalue, not a rvalue. See my SO question here for a more detailed explanation.
This item actually explained a few rules to apply when you write your code. Let me go through them for you:
use
std::move
for rvalue reference andstd::forward
for universal reference respectively, if inside your function there are multiple usages of the reference, you might just want to applystd::move
andstd::forward
for the last usageIf you are returning a rvalue reference passed as a function parameter, the rule above still applies, you have to use
std::move
orstd::forward
to achieve the optimalBut if you are returning a local object, don't use
std::move
because that will invalidate RVO (return value optimisation) for the compiler.
From Item 26 & 27
Avoid overloading on universal references
This is because overloading on universal references can take a very high priority when the compiler tries to resolve overloaded function and thus cause confusion. This is especially true for constructors. But sometimes we cannot avoid this, again, especially for constructors since we have to overload them. In item 27 Scott introduced us some techniques to resolve this issue. I think the most important one is using tag dispatch.
So what is tag dispatch?
<.... revisit item 26 and 27 later ... >
Item 28
This item just states two rules:
Although programmers cannot declare "reference to reference", the compiler is allowed to generate "reference to reference" in certain context.
When we have reference to reference, a rule called reference collapsing comes into play, in short, it states:
If either reference is an lvalue reference, the result is an lvalue ref. Otherwise, it is a rvalue ref.
Top comments (0)