Задано несколько конструкторов копирования - PullRequest
4 голосов
/ 25 октября 2011

В Visual C ++ 2010 у меня есть такой класс:

class MyClass{
public:
    MyClass(){}
    MyClass(MyClass &){/*...*/}   //A
    MyClass(const MyClass &){/*...*/}   //B
    template<typename T> MyClass(T &&t){ static_assert(
        !std::is_same<typename 
        std::remove_cv<typename  std::remove_reference<T>::type>::type, 
        MyClass>::value,
        "Wrapping over wrapping is not allowed!"); } //C
};

int main(int, char**){
    MyClass a;
    const MyClass b(a); //assert fail if line A removed
    auto c=b; //assert fail if line B removed
}
//If both A and B exists
//Warning C4521: multiple copy constructors specified
//Furthermore, if both A and B removed
//No error or warnings; VC2010 accepts peacefully.
//In debug mode you will find the compiler generated trivial copy constructor

В соответствии со стандартом C ++ обе строки A и B считаются конструкторами копирования, а C - конструктором преобразования. Не удивительно, что я получаю предупреждение о том, что я объявил несколько конструкторов копирования. Однако, если я удалю какой-либо из них, static_assert завершится неудачно и код не будет скомпилирован, это означает, что конструктор шаблона получил управление.

Я уверен, что это поведение следует правилу перегрузки функций. Однако это конфликт двух правил? Если A и B являются конструкторами копирования, и один из них был объявлен, любая попытка копирования объектов не должна сбрасываться в шаблон, верно?

Обновление: Согласно N3242, 12.8.7,

"шаблон функции-члена НИКОГДА НЕ УСТАНАВЛИВАЕТСЯ выполнять копирование объекта класса в объект его типа."

правильная реализация должна быть:

  • Не должно произойти сбоя подтверждения при удалении либо A, либо B, либо обоих.
  • Если строка B удалена, конструкция c должна потерпеть неудачу, потому что b является const.
  • Если обе строки удалены, компилятор должен сгенерировать конструктор копирования для класса.
  • Реализация должна предупредить пользователя, если обе строки существуют.

Любой комментарий?

Ответы [ 2 ]

1 голос
/ 25 октября 2011

Прежде всего, template<T> должно быть template <typename T>.

Я использую gcc 4.4.3 на 64-битной Ubuntu Linux, коды ведут себя не так, как вы продемонстрировали в посте.

  • Если ничего не изменилось, коды могут быть скомпилированы без предупреждения. Конструктор A и B вызываются один за другим.
  • Если я прокомментирую строку A, она не будет скомпилирована так, как вы сказали: ошибка в строке const MyClass b(a);. Причина в том, что объект a не является константой, поэтому конструктор B не может быть сопоставлен, и компилятор должен создать экземпляр конструктора шаблона. Конечно, const MyClass и MyClass - это разные типы.
  • Однако, если я прокомментирую только строку B, коды могут быть успешно скомпилированы, и был вызван конструктор копирования шаблона. Объект b является постоянным объектом, поэтому конструкция A не может быть сопоставлена, и компилятор создает экземпляр конструктора шаблона. Тем не менее, остается вопрос: static_assert терпит неудачу или нет? Разница может быть из-за разницы между платформой и компилятором. GCC, кажется, реализует is_same<MyClass&&, MyClass>::value, чтобы быть правдой. Вы можете использовать typeid для распечатки обоих типов.
0 голосов
/ 25 октября 2011

Если A и B являются конструкторами копирования, и один из них был объявлен, любая попытка копирования объектов не должна сбрасываться в шаблон, верно?

Конструктор, который не является конструктором копирования, все еще можно использовать для копирования объектов. В вашем случае для копирования объекта используется конструктор, созданный из шаблона конструктора. Что хорошо.

...