Специальные функции-члены всегда объявляются? - PullRequest
2 голосов
/ 25 декабря 2011

В §12 стандарта каждая специальная функция-член имеет набор правил, которые приводят к implicitly declared as defaulted, и другой набор правил, которые вызывают a defaulted [special member function to be] defined as deleted.

Это создает впечатление (для меня), что существует 3 потенциальных состояния, когда для специальных функций-членов отсутствует объявленная пользователем версия: объявленная и определенная (defaulted), объявленная и неопределенная (deleted)и необъявленный.Это точно?Если да, то какой смысл в отличие от исключения необъявленного параметра?

* declared as defaulted представляется ошибкой, не следует ли ее «определить» как дефолтную?

Ответы [ 2 ]

5 голосов
/ 26 декабря 2011

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

Пример:

Этот класс является конструируемым по умолчанию. Компилятор неявно объявляет для него конструктор по умолчанию.

struct A
{
    template <class ...T>
    A(T...) {}
};

int main()
{
    A a;  // ok
}

Если компилятор объявил для него конструктор по умолчанию, и если этот конструктор по умолчанию был определен как удаленный, то A не будет конструируемым по умолчанию. Это может быть смоделировано с:

struct A
{
    A() = delete;  // pretend the compiler implicitly declared and defined this

    template <class ...T>
    A(T...) {}
};

int main()
{
    A a;
}

error: call to deleted constructor of 'A'
    A a;
      ^

Аналогичные проблемы возникают с конструктором перемещения. Если компилятор решит неявно объявить его и определить как удаленный, то нельзя создать такой класс из значения r, даже если у него есть жизнеспособный конструктор копирования:

#include <type_traits>

struct A
{
    A();
    A(const A&);
    A(A&&) = delete;  // pretend compiler declared and defined
};

int main()
{
    A a = std::declval<A>();
}

error: call to deleted constructor of 'A'
    A a = std::declval<A>();
      ^   ~~~~~~~~~~~~~~~~~

Но если компилятор не неявно не объявляет удаленный конструктор перемещения, то все просто работает:

#include <type_traits>

struct A
{
    A();
    A(const A&);
};

int main()
{
    A a = std::declval<A>();  // ok
}

Действительно, если бы компилятор действительно неявно объявил удаленный конструктор перемещения для A, при перекомпиляции в C ++ 11 было бы очень много сломанного кода C ++ 98/03! : -)

0 голосов
/ 25 декабря 2011

Я не уверен, что согласен с вашим резюме:

Существует три основных состояния: User Defined, Deleted или Compiler Generated

  • объявлено и определено
    • Это означает, что пользователь явно объявил их в классе и предоставил определения.
  • объявлено и удалено
    • Это означает, что пользователь явно объявил их как удаленные (т.е. они недоступны).
  • необъявленная
    • Пользователь не предоставил объявление (и, следовательно, не может предоставить определение).
      В этом случае компилятор сгенерирует версию метода.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...