Подтвердить что ты не робот

Почему нужно настраивать идеальную функцию переадресации?

Почему действует следующий код:

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

Но не:

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

Почему lvalue в примере 2 не разрешается так же, как в примере 1?

Кроме того, почему стандарт считает важным предоставить тип аргумента в std:: forward или simple, выведя его? Просто вызов вперед показывает намерение, независимо от типа.

Если это не стандартная вещь и только мой компилятор, я использую msvc10, что объясняет дерьмовую поддержку С++ 11.

Спасибо

Изменить 1: изменил литерал "Hello World" как std::string ( "Hello World" ), чтобы сделать rvalue.

4b9b3361

Ответ 1

Прежде всего, прочитайте это, чтобы получить полное представление о пересылке. (Да, я передаю большую часть этого ответа в другом месте.)

Подводя итог, пересылка означает, что lvalues ​​остаются lvalues ​​и rvalues ​​остаются rvalues. Вы не можете сделать это с помощью одного типа, так что вам нужно два. Поэтому для каждого пересылаемого аргумента вам нужны две версии для этого аргумента, для которых требуется 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;
};

Затем вы должны остановиться и сделать это следующим образом:

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;
};

Вам нужен только один конструктор. Руководство: если вам нужна ваша собственная копия данных, сделайте эту копию в списке параметров; это позволяет решить скопировать или перейти к вызывающему и компилятору.