std::experimental::optional<T> 实现:Constexpr 构造函数混淆

6

在实现std::experimental::optionalcppreference.com)时,我对一个特定构造函数的规范感到困惑,即:


constexpr optional( const T& value ); // (4)

(来源)

这个构造函数允许在constexpr上下文中构造optional<T>,其中T是一个可平凡销毁的类型。虽然第一个要求,在这种情况下关闭用户提供的析构函数以使optional<T>成为字面类型,很容易解决,但我不知道如何避开在constexpr中不允许使用placement-new的限制。

我原以为应该使用std::aligned_storage<T>来实现optional<T>,以允许不具有默认构造函数并满足任何对齐要求(如果适用)的类型T。但正如我所说,constexpr禁止我在那个特定的构造函数中使用placement new。

我喝太多咖啡了,难道没有明显的解决方案吗?

谢谢


可能是如何使用std :: optional?的重复问题。 - Matriac
2
@Matriac 这是一个关于实现方面的问题。 - nshct
1
一个 union 可能适用于这个特定的构造函数,但我不确定它是否足以处理所有情况。 - user743382
@hvd,我目前正在使用标签分派来替换放置new,以在T是平凡可析构时将其替换为赋值。但我不确定是否会遇到包含诸如std::unique_ptr之类的东西(这将导致类变得平凡可析构),一旦我对包含垃圾的缓冲区进行赋值,它们将尝试删除垃圾指针。 - nshct
1
libc++使用union进行实现;https://llvm.org/svn/llvm-project/libcxx/trunk/include/experimental/optional。gcc libstdc++也是如此;https://gnu.googlesource.com/gcc/+/gcc-5_3_0-release/libstdc++-v3/include/experimental/optional - Niall
请查看这篇精彩的文章 - Tomilov Anatoliy
1个回答

5

我不知道如何在constexpr中避免placement-new的限制。

这是一个正确的诊断,字面类型、constexpr和new表达式不能混合使用。实现std::experimental::optional<T>最直接的方法是使用变体成员。简单来说,必须有一个联合体参与。下面是一个快速草图:

template<typename Val>
struct optional {
    union {
        Val optional_value;
        unsigned char dummy_byte;
    };
    bool filled;

    // post-condition: no-value state
    constexpr optional()
        : dummy_byte {}
        , filled(false)
    {}

    // post-condition: has-value state
    constexpr optional(Val const& val)
        : optional_value(val)
        , filled(true)
    {}

    // other special members omitted for brevity
};

在 Coliru 上实时运行

事实上,旧的一系列optional提案曾经有一个段落介绍技术来证明它提出的要求是合理的。(现在std::experimental::optional在各种候选库基础 TS 中继续存在。)


谢谢。我不知道为什么我一直专注于aligned_storage,但这是正确的解决方案。 - nshct

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接