[英]std::experimental::optional<T> implementation: Constexpr constructor confusion
[英]std::experimental::optional inside constexpr function
我想在constexpr函數中使用可選的習慣用法來輕松澄清變量是否設置。
我用std :: experimental :: optional試過的:
constexpr bool call()
{
std::experimental::optional<bool> r;
r = true; // Error
// Similar error with:
// r = std::experimental::optional<bool>(true);
if (!r)
{
return false;
}
return *r;
}
我得到錯誤: 調用非constexpr函數 - 因此無法進行賦值,因為此操作不能是constexpr( 示例 )。
但是,如果我實現自己的(非常丑陋, 例如 )可選類,它可以工作,因為我沒有實現賦值運算符/構造函數顯式。
template<typename T>
struct optional
{
bool m_Set;
T m_Data;
constexpr optional() :
m_Set(false), m_Data{}
{
}
constexpr optional(T p_Data) :
m_Set(true), m_Data(p_Data)
{
}
explicit constexpr operator bool()
{
return m_Set;
}
constexpr T operator *()
{
return m_Data;
}
};
我如何在相同的上下文中使用std :: .. :: optional並在constexpr函數中進行賦值?
基本上,你不能。 簡單實現的問題是它需要T
是默認構造的 - 如果不是這種情況,這將不起作用。
為了解決這個問題,大多數實現都使用了一個union
或一些可以容納T
(適當對齊的)存儲。 如果你在構造函數中傳遞一個T
,那么一切都很好,你可以直接初始化它(因此它將是constexpr
)。 但是,這里的權衡是,當調用operator=
,復制值可能需要一個新的調用,這不能是constexpr
。
例如,來自LLVM:
template <class _Up,
class = typename enable_if
<
is_same<typename remove_reference<_Up>::type, value_type>::value &&
is_constructible<value_type, _Up>::value &&
is_assignable<value_type&, _Up>::value
>::type
>
_LIBCPP_INLINE_VISIBILITY
optional&
operator=(_Up&& __v)
{
if (this->__engaged_)
this->__val_ = _VSTD::forward<_Up>(__v);
else
{
// Problem line is below - not engaged -> need to call
// placement new with the value passed in.
::new(_VSTD::addressof(this->__val_)) value_type(_VSTD::forward<_Up>(__v));
this->__engaged_ = true;
}
return *this;
}
至於為什么constexpr
新品不是constexpr
,請看這里 。
我如何在相同的上下文中使用std :: .. :: optional並在constexpr函數中進行賦值?
std::optional
意味着保存可能存在或不存在的值。 std::optional
的賦值問題是它必須銷毀舊狀態(調用包含對象的析構函數),如果有的話。 你不能有一個constexpr
析構函數。
原因,瑣碎和整體類型不應該有問題,但我認為概括是為了保持理智。 但是,Assignment可以用於簡單類型的constexpr
。 希望它會得到糾正。 在此之前,你可以扮演你的角色。 :-)
甚至std::optional
的構造函數,你認為是constexpr
,實際上是選擇性constexpr
(取決於所選的對象構造函數是否)。 它的提議可以在這里找到
不幸的是, std::optional
constexpr
支持有些簡陋; constexpr
-enabled成員函數只是(空的和參與的)構造函數,析構函數和一些觀察者,因此您無法更改可選的參與狀態。
這是因為如果不使用對包含對象的放置新的和就地破壞,就沒有辦法為非平凡的可復制類型實現賦值,這在constexpr
上下文中是非法的。 復制和移動構造函數目前同樣適用,盡管可能會因保證復制省略而改變,但無論如何標准將這些特殊成員函數標記為非constexpr
,因此您不能在constexpr
上下文中使用它們。
的修復將是使賦值運算符有條件constexpr
依賴於所包含的類型是否是微不足道的( std::is_trivial_v<T>
在參考實施中對這個問題進行了一些討論; 雖然將標准選項的constexpr
賦值轉換為標准的下一版本可能為時已晚,但沒有什么能阻止你自己編寫(例如通過復制和修復參考實現)。
這是不可能的,如n3527中所述 :
使
optional
的文字類型我們建議
optional<T>
是一個簡單可破壞的T的文字類型。constexpr optional<int> oi{5}; static_assert(oi, ""); // ok static_assert(oi != nullopt, ""); // ok static_assert(oi == oi, ""); // ok int array[*oi]; // ok: array of size 5
通常使
optional<T>
成為文字類型是不可能的:析構函數不可能是微不足道的,因為它必須執行一個操作,可以在概念上描述為:~optional() { if (is_engaged()) destroy_contained_value(); }
仍然可以使析構函數對於
T
本身是微不足道的,它們本身就提供了一個簡單的析構函數,並且我們知道這種帶有編譯時接口的optional<T>
的有效實現 - 除了復制構造函數和移動構造函數 - 是可能的。 因此,我們提出,除了移動和復制構造函數之外,對於簡單可破壞的T
,所有optional<T>
的構造函數,以及觀察者函數都是constexpr。 本提案中提供了參考實施的草圖。
換句話說,即使將其標記為constexpr,也無法為r
分配值。 您必須在同一行中初始化它。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.