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