合理使用 std::forward
10.6.14 ID_unsuitableForward
std::forward 的参数应为“转发引用(forwarding references)”,返回值应直接作为接口的参数,除此之外的使用方式价值有限,且易产生错误。
转发引用是类型为 T&& 的参数,T 为函数模板类型,左值和右值均可与之绑定,可参见 ID_illForwardingReference 的进一步说明。
示例:
struct A { .... };
void foo(A&); // #1
void foo(const A&); // #2
void foo(A&&); // #3
template <class T>
void bar(T&& x) { // Forwarding reference
foo(forward<T>(x)); // Compliant
}
void baz(const A& a) {
A b(a);
bar(b); // Calls #1
bar(a); // Calls #2
bar(A()); // Calls #3
}
例中 bar 接口的参数为转发引用,在 baz 函数中,bar 接口将左值、常量引用和临时对象分别转发给对应的 foo 接口,这种模式称为“完美转发”,std::forward 应在这种模式内使用。
下面给出几种错误示例:
void bar(A&& x) {
foo(forward<A>(x)); // Non-compliant, ‘x’ is not a forwarding reference
}
template <class T>
struct X {
void bar(T&& x) {
foo(forward<T>(x)); // Non-compliant, ‘x’ is not a forwarding reference
}
};
注意,转发引用的类型只能是函数模板类型,非模板和类模板不构成转发引用。
template <class T>
void bar(T&& x) {
T y = forward<T>(x); // Non-compliant, ‘y’ is always an lvalue
foo(y);
}
template <class T>
void bar(T&& x) {
foo(forward<T&>(x)); // Non-compliant, use ‘forward<T>(x)’
}
例中 forward 的返回值应直接作为接口的参数,且只应使用 forward<T>。
相关
依据
ISO/IEC 14882:2011 20.2.3(1)
ISO/IEC 14882:2017 23.2.5(1)