Наиболее сжатый способ отключения копирования и перемещения семантики

Следующее, безусловно, работает, но очень утомительно:

T(const T&) = delete;
T(T&&) = delete;
T& operator=(const T&) = delete;
T& operator=(T&&) = delete;

Я пытаюсь найти наиболее сжатый способ. Будут ли следующие работы?

T& operator=(T) = delete;

Обновление

Обратите внимание, что я выбираю T& operator=(T) вместо T& operator=(const T&) или T& operator=(T&&), потому что он может служить обеим целям.

Ответ 1

Согласно этой диаграмме (Howard Hinnant):

meow

Наиболее кратким способом является =delete переместить оператор присваивания (или переместить конструктор, но это может вызвать проблемы, упомянутые в комментариях).

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

Ответ 2

Пожалуйста, не пытайтесь найти "самый лаконичный способ" написать кусок кода.

Если нет очевидной формы выражения чего-то, что также является очень лаконичным - не ищите, не пытайтесь объяснить языком юриста свой путь к написанию на несколько символов меньше. Зачем? Подумайте о людях, читающих ваш код: если вам нужно обратиться к стандарту, чтобы понять, что ваш код выполняет то, что вы хотите, то и ваши читатели кода тоже. За исключением того, что они не будут знать, чего вы пытаетесь достичь; поэтому они не будут консультироваться со стандартом; так что они просто будут смущены тем, что делает ваш код. Или - некоторые получат это, а некоторые не будут. * 1

В вашем случае, если вы сделаете подмножество этих удалений или воспользуетесь каким-то другим "умным" приемом - как человек, читающий ваш код, скорее всего, я не поймаю вас, не заметив, что вы на самом деле пытаетесь получить все копии и семантика перемещения удалена. И я запутаюсь, думая, что вы пытаетесь сделать что-то еще. На самом деле, на вашем месте я бы даже подумал добавить комментарий:

/* Disabling copy and move semantics because XYZ */
T(const T&) = delete;
T(T&&) = delete;
T& operator=(const T&) = delete;
T& operator=(T&&) = delete;

что еще более "утомительно", но сделает ваши намерения/мотивы абсолютно ясными для ваших будущих читателей.

Там также вопрос о том, что именно причина "XYZ". Некоторые утверждают, что нет веских причин для удаления участников перемещения, и, как правило, это плохая идея. C++ светило Говард Хиннант говорит об этом.

* - вариант по принципу, который я изложил здесь.

Ответ 3

Я предпочитаю наследовать от boost:: noncopyable, тем самым делая намерение незамедлительно понятным и делегируя детали в надежную библиотеку.

#include <boost/core/noncopyable.hpp>

class X: private boost::noncopyable
{
};

Он включает в себя добавление зависимости, но если вы в порядке с этим, это, возможно, очень сжатый и выразительный способ выполнить его.

Ответ 4

Вы можете написать простой struct и наследовать от него:

struct crippled
{
    crippled() = default;

    crippled(const crippled&) = delete;
    crippled(crippled&&) = delete;

    crippled& operator=(const crippled&) = delete;
    crippled& operator=(crippled&&) = delete;
};

Использование:

struct my_class : crippled
{

};

int main()
{
    my_class a;
    auto b = a; // fails to compile
}

Ответ 5

Я считаю, что в этом случае макросы на самом деле более читабельны:

#define NOT_COPYABLE( TypeName ) \
TypeName ( TypeName const& ) = delete; \
TypeName & operator = ( TypeName const& ) = delete;

#define NOT_MOVEABLE( TypeName ) \
TypeName ( TypeName && ) = delete; \
TypeName & operator = ( TypeName && ) = delete;