C++ constexpr std::可选的可能实现

C++ constexpr std::可选的可能实现,c++,c++11,c++14,c++17,C++,C++11,C++14,C++17,我正在尝试使用constepr支持来实现std::optional。用法如下所示: constexpr optional<int> x(123); int arr[*x]; 我还能如何实现这一点呢?您可以使用一个联合体 看看Andrzej是如何做到这一点的: 模板 联合存储 { 无符号字符; T值; constexpr存储_t(平凡_init_t)noexcept:dummy_(){}; 模板 constexpr存储(Args&…Args):值(constexpr_forward

我正在尝试使用
constepr
支持来实现
std::optional
。用法如下所示:

constexpr optional<int> x(123);
int arr[*x];
我还能如何实现这一点呢?

您可以使用一个联合体

看看Andrzej是如何做到这一点的:

模板
联合存储
{
无符号字符;
T值;
constexpr存储_t(平凡_init_t)noexcept:dummy_(){};
模板
constexpr存储(Args&…Args):值(constexpr_forward(Args)…{}
~storage_t()=默认值;
};
模板
结构可选_基
{
布尔初始值;
储存(t)储存(t);;
constexpr optional_base()noexcept:init_(false),storage_(triple_init){};
显式constexpr可选_基(const T&v):init_u(true),storage_v(v){}
显式constexpr可选_基(T&&v):init_(true),存储_(constexpr_move(v)){
模板显式可选\u基(在位\u t,参数&&…参数)
:init_u(true),存储_u(constepr_uforward(args)…{}
模板
显式可选的\u基(in_place\t,std::initializer\u list il,Args&…Args)
:init_(true),storage_(il,std::forward(args)…{}
~optional_base(){if(init_uu)storage_u.value_uu.T::~T();}
};
注:

如果您想要得到一个既支持在
constexpr
函数中的局部变量中使用,又支持在运行时与非平凡可破坏的值一起使用的答案,那么这个解决方案就有一定的复杂性。(可能,您确实希望支持此功能,您不希望您的
constexpr optional
泄漏,或者它不是常规可选的替代品。)

这是因为
constexpr
析构函数必须根据语言规则设置为默认值,但在某些情况下,这必须与调用泛型参数的析构函数的需要相协调


在Andrzej的例子中,通过使用SFINAE并打开
std::is_minality_destructible
切换到
optional_base
类的两个不同实现,一个带有默认析构函数,另一个没有。我在上面的列表中忽略了这一点。如果你想要所有的血淋淋的细节,我建议你读塔尔科夫斯基的代码。< /P>哇,这是我所期望的代码。杰姆斯:欢迎,在C++中实现一个接近语言的特性。你不需要析构函数是
constexpr
,这个DIY选项才能在constexpr上下文中使用吗?@emile:@ChrisBeck因此我的评论。我检查了Andrzej的可选实现,现在我看到他有条件地继承了一个
constepr_optional_base
,如果T是可微破坏的,则没有析构函数。恐怕您的代码片段只展示了如何为运行时案例实现可选存储。
constexpr optional(const T& value)
    noexcept(std::is_nothrow_copy_constructible<T>::value)
    : ...
{
    new (ptr_to_storage) T(value);  // this breaks `constexpr`
}
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(); }
};