簡體   English   中英

std :: experimental ::可選內部constexpr函數

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM