为什么必须模仿完美的转发功能?

Mra*_*anz 18 c++ perfect-forwarding c++11

为什么以下代码有效:

template<typename T1>
void foo(T1 &&arg) { bar(std::forward<T1>(arg)); }

std::string str = "Hello World";
foo(str); // Valid even though str is an lvalue
foo(std::string("Hello World")); // Valid because literal is rvalue
Run Code Online (Sandbox Code Playgroud)

但不是:

void foo(std::string &&arg) { bar(std::forward<std::string>(arg)); }

std::string str = "Hello World";
foo(str); // Invalid, str is not convertible to an rvalue
foo(std::string("Hello World")); // Valid
Run Code Online (Sandbox Code Playgroud)

为什么示例2中的左值不会以与示例1中相同的方式解析?

另外,为什么标准认为需要在std :: forward与简单推导中提供参数类型很重要?无论类型如何,简单地呼唤前方都表现出意图.

如果这不是标准的东西,只是我的编译器,我使用msvc10,这将解释蹩脚的C++ 11支持.

谢谢

编辑1:将文字"Hello World"更改为std :: string("Hello World")以生成rvalue.

GMa*_*ckG 15

首先,阅读本文以全面了解转发.(是的,我在其他地方委托了大部分答案.)

总而言之,转发意味着左值保持左值并且右值保持左值.你不能用一种类型做到这一点,所以你需要两个.因此,对于每个转发的参数,您需要两个版本用于该参数,该函数需要2 N个组合.您可以编写该函数的所有组合,但如果您使用模板,则会根据需要为您生成各种组合.


如果您正在尝试优化副本和移动,例如:

struct foo
{
    foo(const T& pX, const U& pY, const V& pZ) :
    x(pX),
    y(pY),
    z(pZ)
    {}

    foo(T&& pX, const U& pY, const V& pZ) :
    x(std::move(pX)),
    y(pY),
    z(pZ)
    {}

    // etc.? :(

    T x;
    U y;
    V z;
};
Run Code Online (Sandbox Code Playgroud)

然后你应该停下来这样做:

struct foo
{
    // these are either copy-constructed or move-constructed,
    // but after that they're all yours to move to wherever
    // (that is, either: copy->move, or move->move)
    foo(T pX, U pY, V pZ) :
    x(std::move(pX)),
    y(std::move(pY)),
    z(std::move(pZ))
    {}

    T x;
    U y;
    V z;
};
Run Code Online (Sandbox Code Playgroud)

你只需要一个构造函数.指南:如果您需要自己的数据副本,请在参数列表中制作该副本; 这使得决定复制或移动到调用者和编译器.