对于应该如何实现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
?这是标准的缺陷还是什么?
答案 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。