std::experimental::optional 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 (Example)。
但是如果我实现我自己的(非常丑陋,just for example)可选的 class,它会起作用,因为我没有实现赋值 operator/constructor 显式。
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=
时,复制值可能需要 placement-new 调用,不能是 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;
}
为什么placement new不是constexpr
,参见here。
How could I use std::..::optional in the same context with assignment
inside constexpr functions?
std::optional
is meant to hold a value that may or may not be present. The problem with std::optional
's assignment是如果有的话必须销毁旧状态(调用包含对象的析构函数)。而且你不能有一个 constexpr
析构函数。
当然,Trivial 和整数类型应该没有问题,但我认为概括是为了让事情保持理智。但是,可以为普通类型进行赋值 constexpr
。希望它会得到纠正。在此之前,您可以发挥自己的作用。 :-)
连std::optional
的构造函数你以为是constexpr
,其实是选择性的constexpr
(要看被选对象构造函数是不是)。 其提案可见here
不幸的是,constexpr
对 std::optional
的支持有些简陋; constexpr
-启用的成员函数只是(空的和参与的)构造函数、析构函数和一些观察者,所以你不能改变可选的参与状态。
这是因为如果不使用 placement new 和包含对象的就地销毁,就无法实现非平凡可复制类型的赋值,这在 constexpr
上下文中是非法的。目前对于复制和移动构造函数也是如此,尽管这可能会因保证复制省略而改变,但无论如何标准将这些特殊成员函数标记为非 constexpr
,因此您不能在 constexpr
中使用它们上下文。
解决方法是使赋值运算符有条件地 constexpr
取决于包含的类型是否微不足道 (std::is_trivial_v<T>
)。
有人讨论这个问题at the reference implementation;尽管将 constexpr
琐碎的可选值赋值到下一版本的标准中可能为时已晚,但没有什么能阻止您编写自己的代码(例如通过复制和修复参考实现)。
这是不可能的,如 n3527 中所述:
Making optional
a literal type
We propose that optional<T>
be a literal type for trivially
destructible T'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
Making optional<T>
a literal-type in general is impossible: the
destructor cannot be trivial because it has to execute an operation
that can be conceptually described as:
~optional() {
if (is_engaged()) destroy_contained_value();
}
It is still possible to make the destructor trivial for T
's which
provide a trivial destructor themselves, and we know an efficient
implementation of such optional<T>
with compile-time interface —
except for copy constructor and move constructor — is possible.
Therefore we propose that for trivially destructible T
's all
optional<T>
's constructors, except for move and copy constructors,
as well as observer functions are constexpr. The sketch of reference
implementation is provided in this proposal.
换句话说,即使您将其标记为 constexpr,也无法为 r
赋值。您必须在同一行中对其进行初始化。
我想在我的 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)可选的 class,它会起作用,因为我没有实现赋值 operator/constructor 显式。
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=
时,复制值可能需要 placement-new 调用,不能是 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;
}
为什么placement new不是constexpr
,参见here。
How could I use std::..::optional in the same context with assignment inside constexpr functions?
std::optional
is meant to hold a value that may or may not be present. The problem with std::optional
's assignment是如果有的话必须销毁旧状态(调用包含对象的析构函数)。而且你不能有一个 constexpr
析构函数。
当然,Trivial 和整数类型应该没有问题,但我认为概括是为了让事情保持理智。但是,可以为普通类型进行赋值 constexpr
。希望它会得到纠正。在此之前,您可以发挥自己的作用。 :-)
连std::optional
的构造函数你以为是constexpr
,其实是选择性的constexpr
(要看被选对象构造函数是不是)。 其提案可见here
不幸的是,constexpr
对 std::optional
的支持有些简陋; constexpr
-启用的成员函数只是(空的和参与的)构造函数、析构函数和一些观察者,所以你不能改变可选的参与状态。
这是因为如果不使用 placement new 和包含对象的就地销毁,就无法实现非平凡可复制类型的赋值,这在 constexpr
上下文中是非法的。目前对于复制和移动构造函数也是如此,尽管这可能会因保证复制省略而改变,但无论如何标准将这些特殊成员函数标记为非 constexpr
,因此您不能在 constexpr
中使用它们上下文。
解决方法是使赋值运算符有条件地 constexpr
取决于包含的类型是否微不足道 (std::is_trivial_v<T>
)。
有人讨论这个问题at the reference implementation;尽管将 constexpr
琐碎的可选值赋值到下一版本的标准中可能为时已晚,但没有什么能阻止您编写自己的代码(例如通过复制和修复参考实现)。
这是不可能的,如 n3527 中所述:
Making
optional
a literal typeWe propose that
optional<T>
be a literal type for trivially destructible T'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
Making
optional<T>
a literal-type in general is impossible: the destructor cannot be trivial because it has to execute an operation that can be conceptually described as:~optional() { if (is_engaged()) destroy_contained_value(); }
It is still possible to make the destructor trivial for
T
's which provide a trivial destructor themselves, and we know an efficient implementation of suchoptional<T>
with compile-time interface — except for copy constructor and move constructor — is possible. Therefore we propose that for trivially destructibleT
's alloptional<T>
's constructors, except for move and copy constructors, as well as observer functions are constexpr. The sketch of reference implementation is provided in this proposal.
换句话说,即使您将其标记为 constexpr,也无法为 r
赋值。您必须在同一行中对其进行初始化。