std :: отмывание альтернативы pre c ++ 17 - PullRequest
0 голосов
/ 18 января 2019

Это похоже на std::optional, но не хранит лишний бул. Пользователь должен обеспечить доступ только после инициализации.

template<class T>
union FakeOptional { //Could be a normal struct in which case will need std::aligned storage object.
    FakeOptional(){}  //Does not construct T
    template<class... Args>
    void emplace(Args&&... args){
        new(&t) T{std::forward<Args&&>(args)...};
    }
    void reset(){
        t.~T();
    }
    operator bool() const {
        return true;
    }
    constexpr const T* operator->() const {
        return std::launder(&t);

    }
    constexpr T* operator->() {
        return std::launder(&t);
    }
    T t;
};

Если вам интересно, зачем мне такая неясная структура данных, проверьте здесь: https://gitlab.com/balki/linkedlist/tree/master

Вопрос

  1. Можно ли игнорировать std::launder? Наверное, нет.
  2. Поскольку std::launder доступен только в c ++ 17, как реализовать вышеупомянутый класс в c ++ 14? boost::optional и std::experimental::optional должны были нуждаться в подобной функции или они использовали магию, специфичную для компилятора?

Примечание: Пропустить легко, тип объявлен как union. Что означает, что конструктор T действительно не вызывается. Ссылка: https://gcc.godbolt.org/z/EVpfSN

1 Ответ

0 голосов
/ 19 января 2019

Нет, вы не можете.Одна из причин, по которой предлагается std::launder, заключается в том, что std::optional не может быть реализовано в C ++ 14.Вы можете обратиться к этому обсуждению для подробностей.

С другой стороны, вы можете реализовать один без constexpr.Идея состоит в том, чтобы использовать буфер с reinterpret_cast, потому что результат reinterpret_cast всегда будет ссылаться на вновь созданный объект (в C ++ 17 std::launder все еще требуется, но в C ++ 14 это нормально).Например,

template<class T>
struct FakeOptional { 
    FakeOptional(){}  
    template<class... Args>
    void emplace(Args&&... args){
        new(&storage) T{std::forward<Args&&>(args)...};
    }
    void reset(){
        reinterpret_cast<T*>(&storage)->~T();
    }
    operator bool() const {
        return true;
    }
    const T* operator->() const {
        return reinterpret_cast<const T*>(&storage);
    }
    T* operator->() {
        return reinterpret_cast<T*>(&storage);
    }
    std::aligned_storage_t<sizeof(T), alignof(T)> storage;
};

Реализация boost::optional использует эту идею и не реализует семантику constexpr (вы можете обратиться к ее исходному коду дляподробнее).

...