Обоснование неявного копирования и перемещения конструктора С++?

Мое понимание конструктора неявного копирования С++ похоже на

T(T const& x) : 
    base1(x), base2(x) ... , 
    var1(x.var1), var2(x.var2)...
{}

Конструктор перемещения, задание копирования и перемещения также следуют аналогичному шаблону.

Почему не было определено подобное следующему?

T(T const& x) : 
    base1(static_cast<base1 const&>(x)),
    base2(static_cast<base2 const&>(x)) ... , 
    var1(x.var1), var2(x.var2)...
{}

Пример

У меня был класс, который имел неявный конструктор копирования/перемещения/оператор присваивания, а также некоторые конструкторы преобразования. Я делегировал работу какому-то классу реализации.

class common_work //common implementation of many work like classes
{
   common_work(common_work const&) = default;
   common_work(common_work&&) = default;// ... implicit constructors work for me.
   //a forwarding constructor which can take many work like objects
   template<class T, enable_if<work_like<T> > >
   common_work(T&& x) { ... }
};
class work1 //one of the implementation
{
   work1(work1 const& ) = default;
   work1(work1&& ) = default; ...
   common_work impl_;
};

Это было нормально, так как work1 конструкторы копирования/перемещения вызывали конструктор копирования/перемещения для common_work, а конструктор пересылки использовался другими конструкторами [не показано в коде], которые преобразуются из другого типа work.

Тогда я думал унаследовать work1 от common_work для EBO и других причин. Так выглядел новый класс work1

class work1 : private common_work
{
   work1(work1 const& ) = default;
   work1(work1&& ) = default; ...
};

Но так как work1 является классом work_like, внезапно конструктор пересылки стал лучше соответствовать, поскольку конструктор копирования/перемещения для common_work требует static_cast от производного к базовому.

ПРИМЕЧАНИЕ:

  • Подобный пример приводит Скотт Мейерс. , где конструкция копирования запускает конструктор пересылки, поскольку конструктор копирования требует добавления константы, а конструктор пересылки не требует. Но я думаю, что эта проблема возникает из-за неправильного дизайна класса, в то время как проблема здесь связана с тем, что аргумент, передаваемый базовому классу во время неявного копирования/перемещения, не является точным совпадением.
  • Я не могу написать универсальный конструктор/назначение пересылки и удалить неявные, потому что удаленные функции также участвуют в разрешении перегрузки и вызывают ошибку при точном совпадении.
  • В настоящее время решение, которое у меня есть, состоит в том, чтобы сделать common_work как CRTP , то есть тип производного класса, переданный в качестве аргумента шаблона, и в конструкторе пересылки отфильтровать его как enable_if<and_<work_like<T>,not_<is_same<T,Derived> > > >. В противном случае мне придется вручную писать конструктор копирования/перемещения/назначение для work1 и static_cast в базовые классы явно, что является ошибочным, подверженным ошибкам и опасным для обслуживания.

person abir    schedule 18.07.2013    source источник
comment
Возможно, вы могли бы обойти это, усилив ограничение SFINAE, чтобы оно отклоняло T, производные от common_work?   -  person Andy Prowl    schedule 18.07.2013
comment
Это то, что я делаю в настоящее время. Посмотрите на 3-й пункт в разделе ПРИМЕЧАНИЕ. Хотя должно быть не is_same<T,Derived>, а is_same<remove_ref<T>,Derived>   -  person abir    schedule 18.07.2013
comment
Хорошо, извини. последнюю запись не читал :)   -  person Andy Prowl    schedule 18.07.2013
comment
Я не могу тестировать на других компиляторах, но с G++ 4.7.2: тест. Приведение к базе, похоже, выполняется компилятором неявно, если вы не определяете (предоставляете пользователем) копирующий ctor... Можете ли вы протестировать образец на своей платформе (платформах)?   -  person gx_    schedule 18.07.2013


Ответы (1)


Эта проблема обсуждалась на странице багтрекера MSVC++ несколько лет назад (поэтому, если она еще не исправлена, это известная проблема в MSVC++). Стандарт говорит

  • ... база или член инициализируется напрямую соответствующей базой или членом x.

Я тестировал различные компиляторы, когда читал отчет об ошибках, и все они были «волшебным образом преобразованы». Стандарт, по-видимому, ничего не говорит о самых деталях (также о категории значений и квалификаторах c/v) и просто говорит «с соответствующей базой ... x», что, по ИМО, имеет гораздо больше смысла, если вы понимаете, что это означает «не с x, а с соответствующей базой ... of x», а не с тем, что вы передаете ему полный объект (я бы даже сказал, что это может только иметь смысл таким образом) .

person Johannes Schaub - litb    schedule 18.07.2013
comment
Обратите внимание, что специальные функции-члены с явным значением по умолчанию еще не реализованы в MSVC (хотя они заявили, что скоро добавят их в RTM 2013). - person Jesse Good; 19.07.2013