struct Font {
...
// The foreign constructor.
Font(std::function visit) {
visit(*this);
}
};
class Button {
const Font font = Font([] (Font& font) {
font.weight = Weight::VeryBold;
font.slant = Slang::Oblique;
font.halign = Anchor::Left;
});
};
Единственное что мне не нравится, доступа к protected/private полям класса без сеттеров уже не получить, что делает подобный подход чуть менее читабельным.
Здравствуйте, kaa.python, Вы писали:
KP>Довольно элегантное решение для читабельной, одношаговой инициализации сложных структур данных в C++: http://gerardmeier.com/foreign-constructors-cpp KP>В кратце: KP>
KP>Единственное что мне не нравится, доступа к protected/private полям класса без сеттеров уже не получить, что делает подобный подход чуть менее читабельным.
а чем это лучше обычного
const Font font = [] () {
auto font = Font();
font.weight = Weight::VeryBold;
font.slant = Slang::Oblique;
font.halign = Anchor::Left;
return font;
}();
Здравствуйте, kaa.python, Вы писали:
KP>Довольно элегантное решение для читабельной, одношаговой инициализации сложных структур данных в C++: http://gerardmeier.com/foreign-constructors-cpp
Сама идея передачи функции в конструктор интересна. Может быть, где-то ещё пригодится.
Но вот конкретно здесь — есть проблемы.
— тяжеловесная std::function вместо шаблона
— как уже заметил Jack128, вызов может выродиться (у него, правда, ценой копирования, в надежде на NRVO)
Надо подумать, может, и двухфазную инициализацию можно в похожий паттерн всунуть.
Здравствуйте, kaa.python, Вы писали:
KP>Вот что бы мне хотелось здесь, так это получит доступ к приватным полям инициализируемого класса. Но, похоже что, без вариантов тут
Ну так если есть приватные поля, то и способы работы с ними приватные.
Выходов три
class Secret {
private:
int foo_, bar_, buz_, xyz_;
void setup_xyz();
public:
template<class F, class B, class A>
Secret(F do_foo, B do_bar, A do_all) // настроечных функций может быть больше одной ;)
{
foo_ = do_foo(*this); // (1a)
do_bar(bar_); // (1b)
do_all(*this);
}
void setup_buz(); // (2)friend class Xyzzer; // (3)
};
Здравствуйте, kaa.python, Вы писали:
KP>Единственное что мне не нравится, доступа к protected/private полям класса без сеттеров уже не получить, что делает подобный подход чуть менее читабельным.
А еще оно работает только в случае, если мемберы имеют конструкторы по умолчанию.
Ну и кода сильно меньше не получится в любом случае.
Здравствуйте, uzhas, Вы писали:
PM>>Мне больше всего понравился вариант с лямбдой :
U>какие жертвы ради одного const U>оно того не стоит
Как обычно, зависит от задачи. Может потребоваться инициализировать статическую константу или передать временный объект в функцию. В C++03 приходилось создавать рядом вспомогательную функцию, сейчас для этого есть лямбда по месту использования. Синтаксический оверхед, но удобный.
Здравствуйте, kaa.python, Вы писали:
KP>Довольно элегантное решение для читабельной, одношаговой инициализации сложных структур данных в C++: http://gerardmeier.com/foreign-constructors-cpp KP>В кратце: KP>
KP>Единственное что мне не нравится, доступа к protected/private полям класса без сеттеров уже не получить, что делает подобный подход чуть менее читабельным.
Сделай производный класс. Кстати, в его конструкторе можно обращаться к полям и методам короче и есть доступ к protected.
class Button
{
class CustomFont : public Font
{
public:
CustomFont()
{
weight = Weight::VeryBold ;
slant = Slang::Oblique ;
halign = Anchor::Left ;
}
};
const CustomFont font;
};
Здравствуйте, kaa.python, Вы писали:
KP>Здравствуйте, jazzer, Вы писали:
J>>Ну этому способу сто лет в обед, но главное — это не конструктор же, это двухфазка
KP>В каком месте это двухфазка?
У тебя все члены инициализируются (по умолчанию), а потом начинаются присваивания поверх уже инициализированных членов. Инициализировать члены таким способом не удастся, плюс накладывается дополнительное ограничение насчет поддержки конструирования по умолчанию и последующего изменения (присваиванием или еще как) — то есть константные члены тоже идут лесом.
Здравствуйте, kaa.python, Вы писали:
KP>Довольно элегантное решение для читабельной, одношаговой инициализации
Чем паттерн Builder не угодил?
const Font f = FontBuilder().bold(true).strike(false).color(Color.red).build();
Оно, конечно, многошаговое- но так оптимизирующий компилятор разве не вычистит лишние операции?
Здравствуйте, jazzer, Вы писали:
J>В общем, стандартные прелести двухфазки
на самом деле это отличается от двухфазовой инициализации, т.к. к моменту завершения работы конструктора объект полностью инициализирован и находится в консистентном состоянии. готов к использованию.
вдобавок, при таком подходе все равно не получится сделать shared_from_this при инициализации (или что-то уже придумали?), стандартная двухфазка нужна в этом случае
Здравствуйте, Aртёмка, Вы писали:
Aё>const Font f = FontBuilder().bold(true).strike(false).color(Color.red).build();
Aё>Оно, конечно, многошаговое- но так оптимизирующий компилятор разве не вычистит лишние операции?