Rule A18-9-2 (required, implementation, automated)

Forwarding values to other functions shall be done via: (1) std::move if the value is an rvalue reference, (2) std::forward if the value is forwarding reference.

Rationale

The std::move function unconditionally casts an rvalue reference to rvalue, while the std::forward function does the same if and only if the argument was initialized with an rvalue. Both functions should be used as follows: std::move should be used for forwarding rvalue references to other functions, as rvalue reference always bounds to rvalue std::forward should be used for forwarding forwarding references to other functions, as forwarding reference might be bound to lvalue or rvalue Note that parameter of type “auto&&” is also considered as a forwarding reference for the purpose of this rule.

Example

// $Id: A18-9-2.cpp 289436 2017-10-04 10:45:23Z michal.szczepankiewicz $
#include <cstdint>
#include <string>
#include <utility>
class A
{
public:
explicit A(std::string&& s)
: str(std::move(s))
// Compliant - forwarding rvalue reference
{
}

private:
std::string str;
};
class B
{
};
void Fn1(const B& lval)
{
}
void Fn1(B&& rval)
{
}
template <typename T>
void Fn2(T&& param)
{
Fn1(std::forward<T>(param)); // Compliant - forwarding forwarding reference
}
template <typename T>

void Fn3(T&& param)
{
Fn1(std::move(param)); // Non-compliant - forwarding forwarding reference
// via std::move
}
void Fn4() noexcept
{
B b1;
B& b2 = b1;
Fn2(b2);
// fn1(const B&) is called
Fn2(std::move(b1)); // fn1(B&&) is called
Fn3(b2);
// fn1(B&&) is called
Fn3(std::move(b1)); // fn1(B&&) is called
}

See also

HIC++ v4.0 [9]:17.3.2 Use std::forward to forward universal references Effective Modern C++ [13]: Item 25. Use std::move on rvalue references, std::forward on universal references.