Как гарантировать разрешение копирования с помощью std :: option? - PullRequest
3 голосов
/ 04 июня 2019

У меня есть этот тип:

struct immobile {
   // other stuff omitted
   immobile(immobile&) = delete;
   immobile(immobile&&) = delete;
};
immobile mk_immobile();
// e.g. this compiles
// mk_immobile() is a prvalue and i is its result object
immobile i(mk_immobile());

У меня также есть этот шаблон класса:

template<typename T>
struct container {
    std::variant<T, other_stuff> var;
    template<typename... Args>
    container(Args&&... args)
    : var(std::in_place_index<0>, std::forward<Args>(args)...) {}
};

Я хочу построить container вокруг объекта, созданного mk_immobile(),с объектом immobile, используемым для инициализации одного из вариантов var.

container<immobile> c(mk_immobile());

Однако это не работает.Например, конструктор std::variant хочет std::is_constructible_v<immobile, immobile>, что не выполняется.Хуже того, даже эта упрощенная версия дает сбой:

template<typename T>
struct demonstration {
    T t;
    template<typename... Args>
    demonstration(Args&&... args) : t(std::forward<Args>(args)...) {}
};
demonstration<immobile> d(mk_immobile());

Что, по-видимому, означает, что std::forward, на самом деле, не идеально вперед - prvalues ​​не передаются как prvalues.(Это имеет смысл для меня; я не думаю, что это было бы возможно.) Я могу заставить demonstration работать, изменив его на следующее:

template<typename T>
struct demonstration {
    T t;
    template<typename F>
    demonstration(F&& f) : t(std::forward<F>(f)()) {}
};
demonstration<immobile> d([] { return mk_immobile(); });

Но я не вижу способа изменитьcontainer аналогичным образом.Как мне изменить container, чтобы он мог создать std::variant (или другой теговый союз) из значения?Я могу изменить container, но не могу изменить immobile.

1 Ответ

1 голос
/ 04 июня 2019

Вы злоупотребляете кастами

template<typename F>
struct initializer
{
    F f;
    template<typename T>
    operator T()
    {
        return f();
    }
};

template<typename F>
initializer(F&&) -> initializer<F>;

И использовать как

container<immobile> c{initializer{[]{
    return mk_immobile();
}}};
...