C++ std可选复制构造函数

C++ std可选复制构造函数,c++,c++17,C++,C++17,我对如何实现std::optional的复制构造函数以满足成为constexpr的要求感到非常困惑 请注意,Stackoverflow上还有许多其他类似问题,例如: 但是,这两个问题实际上都不是关于复制构造函数的问题。我特别询问复制构造函数,函数签名(来自)如下: constexpr optional( const optional& other ); 现在,我已经读了足够多的关于std::optional,了解了基本知识。实现者犯的一个典型错误是尝试使用std::aligned

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

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

但是,这两个问题实际上都不是关于复制构造函数的问题。我特别询问复制构造函数,函数签名(来自)如下:

constexpr optional( const optional& other );

现在,我已经读了足够多的关于
std::optional
,了解了基本知识。实现者犯的一个典型错误是尝试使用
std::aligned_存储来实现它。由于placement new无法在
constepr
中工作(至少在C++17中是这样),因此这将不起作用。相反,需要使用联合类型,以便可以直接构造它。比如:

struct dummy_type {};

union optional_impl
{
  dummy_type m_dummy;
  T m_value;
};
好吧,但还是。。。我仍然不知道我们应该如何满足将复制构造函数实现为
constexpr
的要求。问题是在复制构造函数中,我们需要检查
other.has\u value()
是否为true。如果是,我们希望直接复制
*other
,否则我们只希望初始化
m_dummy
。但是我们如何在
constexpr
copy构造函数中表达这个条件决策呢

constexpr optional( const optional& other ) : m_dummy{}
{
  if (other.has_value()) new (&m_value) T(*other); // Wrong! Can't use placement new
}
我能看到这种效果的唯一方法是使用新的布局

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

事实上。。。他们只是使用新的布局。事实上,复制构造函数不是event
constexpr
(我想这是一个缺陷)

下面是另一个实现:

再说一次,他们只是使用新的布局


那么,
optional(const optional&)
如何实现为
constexpr
?这是标准中的一个缺陷还是什么?

看起来这是C++17(std::optional是在C++17中添加的),这意味着仅当参数是compiletime时,constexpr才会应用于函数

在本例中,它只是意味着如果函数的所有参数都是constexpr,并且可以在constexpr中执行,那么它实际上就是constexpr


否则,它的行为与任何其他复制构造函数一样。

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

。。。如果
是可复制的
真的
,则此构造函数应为
constexpr
构造函数

在这种情况下,工会也将是微不足道的可复制,因此没有问题

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


在C++20中,由于以下原因,措辞发生了变化。然而,我认为这并没有改变
constexpr
要求。如果
T
是可复制的,那么构造函数是可复制的,这意味着它也是
constexpr
。如果
T
不是可复制的,那么标准没有规定构造函数必须在常量表达式中可用,因此没有这样的要求。

为什么要检查?你不能把
其他的
的联合复制到
这个
的吗?但是如果联合有一个非平凡的复制构造函数呢?哦,是的。如果成员为
std::string
,则不会有复制构造函数。请注意
emplace
不是
constexpr
。我不希望标准要求复制构造函数只使用constexpr友好的机制来初始化对象,而
emplace
在“实际需要做些什么”路径上执行相同的操作时不必这样做。因此,我怀疑
constexpr
仅适用于复制自对象断开的情况。@chris您不能更改联合的活动成员(在C++17中)或将新对象放置在常量表达式中,但可以使用隐式定义的复制构造函数初始化和复制联合。因此,复制构造在任何一种情况下都是可能的(如果T是可复制的),但是
emplace
不是。问题是他们首先要问的是如何将复制构造函数实现为constexpr。它只是一个constexpr的构造函数,这没什么new@JohnkaS对于要标记为
constexpr
的问题,需要有一组有效的参数,使执行在编译时可行。如果此类参数集不存在,则无法将函数标记为
constexpr
。此引用来自哪个版本的标准?与上的草稿不匹配。@Holt当前的草稿(C++17)。@Holt当前草稿有不同的措辞,这让我感到惊讶。我会研究一下。@Holt C++20允许在constexpr函数中使用
new
,因此措辞很可能已更改。@Nathano,但只能使用全局可替换(分配)分配函数,因此仍然无法将新的存储放在分配的存储中。你是如何实现它的?