Таможенный обменный образец

Как я понимаю, идиома «копируй и меняй», у нее есть недостаток, заключающийся в том, что ей нужен код болельщика. Рассмотрим простую структуру «просто держи всех этих чертовски лимонов»:

struct MuchData {
private:
std::string one, two;
int three;
std::vector<Something> four;
MyType five;
MyOtherType six, seven;
unsigned long long int still_overflows;

public:
MuchData() : one("."), two("/"), three(0), four(), five(), six(-1), seven(0), still_overflows(0)
{ }

MuchData(const MuchData& rhs) : one(rhs.one), two(rhs.two), three(rhs.three), four(rhs.four), five(rhs.five), six(rhs.six), seven(rhs.seven), still_overflows(rhs.still_overflows)
{ }

MuchData(MushData&& old) : one("."), two("/"), three(0), four(), five(), six(-1), seven(0), still_overflows(0)
{ swap(*this, old); }

MuchData& operator=(MuchData old) { swap(*old, this); return *this; }

friend void swap(MuchData& left, MushData&right) {
using std::swap;

swap(left.one, right.one);
swap(left.two, right.two);
swap(left.three, right.three);
swap(left.four, right.four);
swap(left.five, right.five);
swap(left.six, right.six);
swap(left.seven, right.seven);
swap(left.still_overflows, right.still_overflows);
}

// And now we can go and do something interesting
};

С инициализаторами, написанными на

: one(".")
, two("/")
, three(0)
// etc.

стиль, этот код занимает еще больше места. А также MyType а также MyOtherType вероятно, также определены с помощью этой техники … есть ли способ уменьшить количество повторений здесь? Например, при добавлении новых полей очень легко забыть добавить соответствующие swap(...) линия, которая вызывает загадочную нарезку.

2

Решение

Одна вещь, которую вы могли бы сделать, это хранить членов в std::tuple и предоставьте им именованные методы доступа, например так:

struct MuchData {
private:
std::tuple<std::string, std::string, int, std::vector<Something>, MyType, MyOtherType, unisgned long long> data;

std::string& one() { return std::get<0>(data); }
const std::string& one() const { return std::get<0>(data); }

//etc.
};

Да, вы меняете один шаблон на другой, но вы будете писать имена только один раз; например, синтаксис конструктора будет гораздо более кратким. И даже если вы забудете добавить аксессор, swap() будет работать очень хорошо (как это будет просто swap() кортежи).

С C ++ 1y, вы даже можете использовать auto& а также const auto& для возвращаемого типа аксессоров, устраняя еще больше дублирования.

2

Другие решения

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

class MuchData {
std::string one{"."};
std::string two{"/"};
// ...

Тогда конструктор по умолчанию и перемещение становятся тривиальными.

MuchData() = default;

MuchData(MuchData&& o) { swap(*this, o); }

И вы можете по умолчанию конструктор копирования:

  MuchData(const MuchData&) = default;
1