gpt4 book ai didi

c++ - 在这个简单的例子中,为什么 std::optional 的赋值运算符不能用于编译时上下文?

转载 作者:行者123 更新时间:2023-12-01 23:19:58 24 4
gpt4 key购买 nike

在编译器浏览器(以及阅读 cppref.com 上的 std::optional)半小时后,我放弃了。除了我不明白为什么这段代码不能编译之外,没什么好说的。有人请解释一下,如果有的话,也许可以告诉我一种解决方法?我在这里使用的 std::optional 的所有成员函数都是 constexpr,并且确实应该在编译时可计算,因为这里的可选类型 - size_t - 是原始标量类型。

#include <type_traits>
#include <optional>

template <typename T>
[[nodiscard]] constexpr std::optional<size_t> index_for_type() noexcept
{
std::optional<size_t> index;
if constexpr (std::is_same_v<T, int>)
index = 1;
else if constexpr (std::is_same_v<T, void>)
index = 0;

return index;
}

static_assert(index_for_type<int>().has_value());

https://godbolt.org/z/YKh5qT4aP

最佳答案

让我们简单一点:

constexpr std::optional<size_t> index_for_type() noexcept
{
std::optional<size_t> index;
index = 1;
return index;
}

static_assert(index_for_type().has_value());

index = 1;你试图在 assignment operators 中调用的候选人是#4:

template< class U = T >
optional& operator=( U&& value );

请注意,这个候选不是最初制作的 constexpr在 C++20 中,它是最近的 DR ( P2231R1 )。 libstdc++ 尚未实现此更改,这就是您的示例无法编译的原因。到目前为止,它是完全正确的 C++20 代码。图书馆还没有完全跟上。


Marek's 的原因建议作品:

constexpr std::optional<size_t> index_for_type() noexcept
{
std::optional<size_t> index;
index = size_t{1};
return index;
}

static_assert(index_for_type().has_value());

是因为不是调用赋值运算符#4 (否则出于同样的原因它会继续不起作用,只是在这个实现中还不是 constexpr),它切换到调用运算符 #3 (即 constexpr ):

constexpr optional& operator=( optional&& other ) noexcept(/* see below */);

为什么是这个?因为#4有这个约束:

and at least one of the following is true:

  • T is not a scalar type;
  • std::decay_t<U> is not T.

在这里,Tsize_t (它是 optional 特化的模板参数)和 U是参数类型。在原来的情况下,index = 1 , Uint这使得第二个项目符号保持不变( int 实际上不是 size_t )因此这个赋值运算符是有效的。但是当我们把它改成index = size_t{1} , 现在 U变成 size_t , 所以第二个项目符号也是假的,我们失去了这个赋值运算符作为候选。

这留下了复制分配和移动分配作为候选,后者更好。移动任务 constexpr在此实现中,它有效。


当然,更好的实现仍然是避免赋值并且只是:

constexpr std::optional<size_t> index_for_type() noexcept
{
return 1;
}

static_assert(index_for_type().has_value());

或者,在原来的函数中:

template <typename T>
[[nodiscard]] constexpr std::optional<size_t> index_for_type() noexcept
{
if constexpr (std::is_same_v<T, int>) {
return 1;
} else if constexpr (std::is_same_v<T, void>) {
return 0;
} else {
return std::nullopt;
}
}

这工作得很好,即使在 C++17 中也是如此。

关于c++ - 在这个简单的例子中,为什么 std::optional 的赋值运算符不能用于编译时上下文?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/68230863/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com