std可选复制构造函数

Sil*_*ler 4 c++ c++17

我对于应该如何std::optional实现复制构造函数以满足存在的要求感到非常困惑constexpr

请注意,在Stackoverflow上还有许多其他问题类似的问题,例如:

如何实现std :: optional的副本构造函数?

std :: Optional实现为union vs char [] / aligned_storage

但是,这两个问题都没有真正询问“ COPY CONSTRUCTOR”。我专门询问具有功能签名(从https://en.cppreference.com/w/cpp/utility/optional/optional)的副本构造函数,如下所示:

constexpr optional( const optional& other );
Run Code Online (Sandbox Code Playgroud)


现在,我已经阅读了足够std::optional的知识,以了解基础知识。实现者通常犯的一个错误是尝试使用来实现它std::aligned_storage。由于new放置不能在中使用constexpr(至少在C ++ 17中),因此将不起作用。相反,需要使用联合类型,以便可以直接构造它。就像是:

struct dummy_type {};

union optional_impl
{
  dummy_type m_dummy;
  T m_value;
};
Run Code Online (Sandbox Code Playgroud)

好的,但是仍然...我仍然看不到应该如何满足将副本构造函数实现为的要求constexpr。问题是在复制构造函数中,我们需要检查是否other.has_value()为真。如果是,我们要直接复制*other,否则我们只想初始化m_dummy。但是,我们如何在constexpr复制构造函数中表达此条件决定呢?

constexpr optional( const optional& other ) : m_dummy{}
{
  if (other.has_value()) new (&m_value) T(*other); // Wrong! Can't use placement new
}
Run Code Online (Sandbox Code Playgroud)

我看到此工作的唯一方法是使用新的展示位置。

所以我检查了一些实际的实现,例如这里的gcc实现:

https://github.com/gcc-mirror/gcc/blob/master/libstdc%2B%2B-v3/include/std/optional#L248

实际上,他们只是使用新的展示位置。实际上,复制构造函数不是事件constexpr(我认为这是一个缺陷)。

这是另一个实现:

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

同样,他们只是使用新的展示位置。

那么如何才能optional(const optional&)实现为constexpr?这是标准中的缺陷吗?

Bri*_*ian 5

对于C ++ 17,请参见[optional.ctor] / 6:

...如果is_trivially_copy_constructible_v<T>true,则此构造函数应为constexpr构造函数。

在这种情况下,联合也将是可复制的,因此没有问题。

在所有其他情况下,constexpr即使不能在常量表达式中使用构造函数,该构造函数仍将携带说明符。没关系:constexpr只要函数模板(或类模板的成员函数)具有至少一个可能在常量表达式中使用的实例化,就可以对其进行声明。([dcl.constexpr] / 6)

在C ++ 20中,由于P0602R4,措辞已更改。但是,我认为这并没有改变constexpr要求。如果T是普通可复制的,则构造函数是普通的,这意味着它也是constexpr。如果T不是普通可复制的,则标准不会说构造函数必须在常量表达式中可用,因此没有这样的要求。