объединяя два конструктора, которые копируют и перемещают - PullRequest
7 голосов
/ 12 сентября 2011

В настоящее время в одном из моих шаблонов игрушечных классов есть два конструктора, которые очень похожи:

optional(const T& x)
{
    construct(x);
}

optional(T&& x)
{
    construct(std::move(x));
}

Могу ли я объединить их в один шаблон конструктора, или это как-то изменит семантику?

template<typename U>
optional(U&& x)
{
    construct(std::forward<U>(x));
}

Ответы [ 4 ]

4 голосов
/ 12 сентября 2011

Шаблонный конструктор никогда не будет (как считает компилятор) конструктором копирования, извините.

2 голосов
/ 12 сентября 2011

Изменяет способ взаимодействия таких черт, как std::is_constructible и std::is_convertible с optional. Например, дано:

class A {};

int main()
{
    std::cout << std::is_constructible<optional<A>, int>::value << '\n';
};

Ваш оригинальный код будет распечатан:

0

Но ваш новый код будет распечатан:

1

Если это нежелательно и вы все еще хотите использовать новый код, вы можете enable_if ограничить U допустимыми типами.

Единственная другая возможная проблема, которую я вижу, - это если T может быть ссылочным типом (например, int&). В этом случае второй конструктор вашего исходного кода выглядит подозрительно, так как он передается в rvalue, и вы, возможно, пытаетесь связать это rvalue с неконстантной ссылкой lvalue (не могу сказать точно). Если T никогда не может быть ссылочным типом, не нужно беспокоиться об этом.

1 голос
/ 12 сентября 2011

О, конструкция не является конструктором, это шаблон функции-члена.

Тогда, возможно, семантика будет другой.Ваш исходный набор перегрузки передает либо ссылку lvalue на const, либо ссылку rvalue на non-const.Версия шаблона также может передавать ссылку lvalue на non -const.(Я игнорирую rvalue ссылки на const.)

По всей вероятности, хотя construct либо объявляется принимающим U&& (иначе ваша предыдущая перегрузка, которая перемещает T, не будет работать), и вв этом случае должен иметь дело с неконстантными l-значениями или объявлен принимающим U const&, и в этом случае он безвреден.

0 голосов
/ 12 сентября 2011

Если у вас есть хотя бы construct(const T& x) и, возможно, добавлено construct(T&& x), и ваш объект типа U может быть преобразован в объект типа T, я думаю, у вас все будет хорошо ...

  1. Постоянная ссылка l-типа типа U будет привязана к construct(const T& x)
  2. Непостоянная ссылка на l-значение типа U будет привязана к construct(const T& x)
  3. Временное значение r типа U будет привязано к construct(T&& x) или construct(const T& x), если эталонная версия значения r не определена
  4. Постоянная ссылка r-типа типа U будет привязана к construct(const T& x)
...