14

它就像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

4

1 回答 1

4

不,你不能。提出的原因之一std::launderstd::optional在 C++14 中无法实现。您可以参考此讨论以获取详细信息。

另一方面,您可以实现一个没有constexpr. 这个想法是使用缓冲区,reinterpret_cast因为结果reinterpret_cast将始终引用新创建的对象(在 C++17std::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语义(具体可以参考它的源码)。

于 2019-01-19T04:14:56.947 回答