constexpr std ::可选的可能实现

constexpr std::optional possible implementation

本文关键字:实现 constexpr std      更新时间:2023-10-16

我正在尝试以constexpr支持作为练习来实现std::optional。用法将是:

constexpr optional<int> x(123);
int arr[*x];

尝试实施此功能时,我得到了一个我无法解决的问题:在optional<T>对象中,我使用std::aligned_storage_t<sizeof (T), alignof (T)>对象存储该值,并在optional<T>的构造器中使用新的位置来构造值进入存储。但是新的位置不能在constexpr构造函数中使用:

constexpr optional(const T& value)
    noexcept(std::is_nothrow_copy_constructible<T>::value)
    : ...
{
    new (ptr_to_storage) T(value);  // this breaks `constexpr`
}

我还能如何实现?

您可以使用联合。

查看Andrzej的工作方式:

https://github.com/akrzemi1/optional/blob/master/optional.hpp#l282

template <class T>
union storage_t
{
    unsigned char dummy_;
    T value_;
    constexpr storage_t( trivial_init_t ) noexcept : dummy_() {};
    template <class... Args>
    constexpr storage_t( Args&&... args ) : value_(constexpr_forward<Args>(args)...) {}
    ~storage_t() = default;
};

template <class T>
struct optional_base
{
    bool init_;
    storage_t<T> storage_;
    constexpr optional_base() noexcept : init_(false), storage_(trivial_init) {};
    explicit constexpr optional_base(const T& v) : init_(true), storage_(v) {}
    explicit constexpr optional_base(T&& v) : init_(true), storage_(constexpr_move(v)) {}
    template <class... Args> explicit optional_base(in_place_t, Args&&... args)
        : init_(true), storage_(constexpr_forward<Args>(args)...) {}
    template <class U, class... Args, TR2_OPTIONAL_REQUIRES(is_constructible<T, std::initializer_list<U>>)>
    explicit optional_base(in_place_t, std::initializer_list<U> il, Args&&... args)
        : init_(true), storage_(il, std::forward<Args>(args)...) {}
    ~optional_base() { if (init_) storage_.value_.T::~T(); }
};

注意:

如果要获得一个支持在constexpr函数中的局部变量中使用的答案,并且在运行时将其与不可损害的值一起使用,则该解决方案存在一些复杂性。(可能,您确实想支持此,您不希望您的constexpr optional泄漏,或者不是常规可选的替换。)

这是因为必须根据语言规则默认constexpr破坏者,但是在某些情况下必须调用通用参数的destructor。

在Andrzej的示例中,通过使用SFINAE并打开std::is_trivially_destructible来解决此问题,以切换到optional_base类的两个不同的实现,一个是带有默认破坏者的,一个没有。我在上面的清单中省略了这一点。如果您想要所有的血腥细节,我建议您阅读Andrzej的代码。