std可选副本构造函数

时间:2019-10-31 20:30:10

标签: c++ c++17

对于应该如何实现std::optional的副本构造函数以满足constexpr的要求,我感到非常困惑。

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

How to implement std::optional's copy constructor?

std::optional implemented as union vs char[]/aligned_storage

但是,这些问题都没有真正问到有关COPY CONSTRUCTOR的问题。我专门询问具有函数签名(来自https://en.cppreference.com/w/cpp/utility/optional/optional)的副本构造函数,如下所示:

constexpr optional( const optional& other );


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

struct dummy_type {};

union optional_impl
{
  dummy_type m_dummy;
  T m_value;
};

好的,但是仍然...我仍然看不到我们应该如何满足将复制构造函数实现为constexpr的要求。问题是在复制构造函数中,我们需要检查other.has_value()是否为true。如果是的话,我们想直接复制*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
}

我唯一能看到此效果的方法是使用新的展示位置。

所以我检查了一些实际的实现,例如这里的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?这是标准的缺陷还是什么?

2 个答案:

答案 0 :(得分: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不能被普通复制,则标准不会说构造函数必须在常量表达式中可用,因此没有这样的要求。

答案 1 :(得分:-4)

由于这是C ++ 17(在c ++ 17中添加了std :: optional),这意味着constexpr仅在参数为编译时时才会应用于函数。

在这种情况下,这仅意味着如果该函数的所有参数都是constexpr且可以执行constexpr,那么它实际上就是constexpr。

否则,它的行为就像任何其他复制ctor。