Как я понимаю, идиома «копируй и меняй», у нее есть недостаток, заключающийся в том, что ей нужен код болельщика. Рассмотрим простую структуру «просто держи всех этих чертовски лимонов»:
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(...)
линия, которая вызывает загадочную нарезку.
Одна вещь, которую вы могли бы сделать, это хранить членов в 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&
для возвращаемого типа аксессоров, устраняя еще больше дублирования.
Вы можете использовать инициализаторы в классе, чтобы уменьшить дублирование между конструкторами, которые инициализируют поля их стандартными значениями:
class MuchData {
std::string one{"."};
std::string two{"/"};
// ...
Тогда конструктор по умолчанию и перемещение становятся тривиальными.
MuchData() = default;
MuchData(MuchData&& o) { swap(*this, o); }
И вы можете по умолчанию конструктор копирования:
MuchData(const MuchData&) = default;