C++ 正确使用std::流槽

C++ 正确使用std::流槽,c++,c++17,C++,C++17,我想确认我正确使用了std::launder(…)确保我正确理解它的用法 我在C++中创建了一个结果>代码>。 模板 类结果存储{ 使用type=typename std::aligned_storage::type; 公众: 显式constexpr ResultStorage(const Ok&)noexcept:tag(ResultTag::Ok){ 显式constexpr ResultStorage(const Ok&&)noexcept:tag_(ResultTag::Ok){ 显式co

我想确认我正确使用了
std::launder(…)
确保我正确理解它的用法

<>我在C++中创建了一个结果>代码>。
模板
类结果存储{
使用type=typename std::aligned_storage::type;
公众:
显式constexpr ResultStorage(const Ok&)noexcept:tag(ResultTag::Ok){
显式constexpr ResultStorage(const Ok&&)noexcept:tag_(ResultTag::Ok){
显式constexpr ResultStorage(const Err&Err)noexcept(std::is_nothrow_copy_constructible())
:标记(结果标记::错误){
新建(&error_)E(err.get_error());
}
显式constexpr ResultStorage(const Err&&Err)noexcept(std::is_nothrow_move_constructible())
:标记(结果标记::错误){
新建(&error_)E(std::move(err.get_error());
}
~ResultStorage()=默认值;
[[nodiscard]]constexpr E&get_error()&noexcept{
断言错误(标记错误);
return*std::流槽(重新解释铸件(&R));
}
//为简洁起见省略了代码
私人:
结果表位;
类型错误;
模板
好友类result::result;
};
在代码中,我使用
使用type=typename std::aligned\u storage::type作为我的存储类型。我相信,当我从函数返回错误类型时,我需要使用
std::launder(…)
,如下所示:

[[nodiscard]]constexpr E&get_error()&noexcept{
断言错误(标记错误);
return*std::流槽(重新解释铸件(&R));
}
我认为我需要使用
std::launder(…)
的原因是,由于传入的错误类型可能是具有
const
值的结构,因此如果我不使用
std::launder(…)
然后在第一次初始化时,它将引用
const
成员值,如果要重用此分配的存储,它将始终引用初始
const
成员值

我对std::launder有一个基本的了解,所以如果能解释一下什么情况下需要使用它,我将不胜感激。我已经看过这个函数的CPPPreference,但仍然觉得它相当神秘


注意:完整的impl可以在上找到。

我不会冒险猜测
std::launder
,但是您的代码有另一个问题,解决它将使
std::launder
不再需要:

new (&error_) E(err.get_error());
(reinterpret_cast<E*>(&error_);
并且仅使用
ptr
访问存储的对象。这也将使不再需要
std::launder


当你看到C++的低级时,会有很多微妙的陷阱。

我想在你的例子中,<代码>错误> <代码>类型可以是<代码> STD::可选< /COD>。这将大大简化您的设计。是的,我不反对使用
std::optional
会更简单。我没有这样做,因为我想尝试从“零开始”实现一些东西,尽可能少地从标准库获得帮助。我当然考虑过使用
std::optional
,但我认为这将是一种有趣的方式来实现它并分析最终的实现。编辑:最后它确实引出了这个问题,因此我认为从学习的角度来看,它实现了我想要的。相关:感谢您指出这一点,重新阅读
std::aligned_storage
上的页面,我在代码中遇到了另一个潜在的错误。我将专门研究std::is_standard_layout
,并且只在问题中的代码为真时才使用。
// class data member:
E* ptr = nullptr;

// then:
ptr = new (&error_) E(err.get_error());