У меня есть раздражающий сценарий, в котором мне нужно отложить инициализацию некоторого объекта state
и позволить пользователю создать его по требованию. Э.Г.
// user code
context c;
// ...do something...
c.initialize_state(a, b, c);
// library code
class context
{
private:
class state
{
state(A a, B b, C c);
state(const state&) = delete;
state(state&&) = delete;
};
std::optional<state> _state; // or `boost::optional`
public:
template <typename... Xs>
void initialize_state(Xs&&... xs)
{
_state.emplace(std::forward<Xs>(xs)...);
}
};
Как видно из приведенного выше кода, интерфейс context::initialize_state
сообщает пользователю ничего о том, как инициализировать context::_state
. Пользователь вынужден посмотреть на реализацию initialize_state
, а затем посмотреть на state::state
, чтобы понять, что следует передать на initialize_state
.
Я мог бы изменить initialize_state
на ...
void initialize_state(A&& a, B&& b, C&& c)
{
_state.emplace(std::move(a), std::move(b), std::move(c));
}
... но это имеет существенный недостаток: существует дублирование кода с state::state
, которое необходимо поддерживать вручную в случае изменения типов аргументов.
Можно ли как-то получить лучшее из обоих миров (СУХОЙ и удобный интерфейс)? Обратите внимание, что state
нельзя перемещать / копировать.