我想在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(Example)。
但是如果我实现自己的(非常丑陋的,just for example)可选类,它就可以工作,因为我没有实现赋值运算符/构造函数显式。
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函数中进行赋值?
答案 0 :(得分:4)
基本上,你不能。简单实现的问题在于它需要as.factor
是默认构造的 - 如果不是这样的话,这将无法正常工作。
为了解决这个问题,大多数实现使用T
或一些(适当对齐的)存储,可以容纳union
。如果你在构造函数中传递T
,那么一切都很好,你可以直接初始化它(因此它将是T
)。但是,这里的权衡是,在调用constexpr
时,复制值可能需要一个新的调用,不能是operator=
。
例如,来自LLVM:
constexpr
至于为何新展示位置不是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;
}
,请参阅here。
答案 1 :(得分:1)
我如何在具有赋值的相同上下文中使用std :: .. :: optional 在constexpr函数内部?
std::optional
旨在保留可能存在或不存在的值。 std::optional
's assignment的问题是它必须销毁旧状态(调用包含对象的析构函数),如果有的话。你不能拥有constexpr
析构函数。
原因,琐碎和整体类型不应该有问题,但我认为概括是为了保持理智。但是,对于普通类型,可以对constexpr
进行分配。希望它会得到纠正。在此之前,你可以扮演你的角色。 : - )
即使std::optional
的构造函数您认为是constexpr
,实际上也是constexpr
(取决于所选对象构造函数是否为)。 可以找到其提案here
答案 2 :(得分:1)
不幸的是,constexpr
中的std::optional
支持有点简陋;启用constexpr
的成员函数只是(空的和参与的)构造函数,析构函数和一些观察者,因此您无法更改可选的参与状态。
这是因为如果不使用对所包含对象的放置新的和就地破坏,就无法实现非平凡可复制类型的赋值,这在constexpr
上下文中是非法的。复制和移动构造函数目前同样适用,尽管可能会因保证复制省略而改变,但无论如何标准将这些特殊成员函数标记为非constexpr
,因此您无法在constexpr
中使用它们上下文。
修复方法是使赋值运算符有条件constexpr
取决于包含的类型是否微不足道(std::is_trivial_v<T>
)。
对此问题进行了一些讨论at the reference implementation;虽然将constexpr
作为普通选项的Runtime
分配到标准的下一版本可能为时已晚,但没有什么可以阻止你编写自己的(例如通过复制和修复参考实现)。
答案 3 :(得分:1)
这是不可能的,如n3527中所述:
使
optional
为文字类型我们建议
optional<T>
是一个简单的文字类型 可破坏的T&#39。s。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
分配值。您必须在同一行中初始化它。