C++20中对聚合类型使用std::make_optional是否合法?GCC和Clang谁正确
问题1:GCC和Clang哪一个符合C++20标准要求?
GCC的实现符合C20标准,Clang属于未完全实现标准特性导致的编译失败。
这个差异来源于C20引入的P0960R3提案(允许使用圆括号初始化聚合类型):该提案正式允许聚合类型用圆括号完成初始化,同时修改了std::is_constructible的判定规则,只要参数列表可以用于聚合初始化对应类型,std::is_constructible_v<T, Args...>就会返回true。
而std::optional的emplace、std::in_place构造、std::make_optional这类API的约束条件恰好是std::is_constructible_v<T, Args...>,因此给出的代码在符合C++20标准的实现中应该正常编译,Clang是因为还未完整落地P0960R3的所有规则才会报错。
问题2:适配Clang的零开销写入方案
首先需要明确:你提到的std::optional<MyStruct> ms{MyStruct{3}}这类写法在C17及以上版本中不存在额外的拷贝开销:C17引入了强制复制消除规则,MyStruct{3}作为纯右值会直接在std::optional的内部存储上构造,不会产生临时对象的拷贝、移动操作,哪怕关闭优化也不会有额外开销。
如果想要更明确的原位构造写法,也可以选择以下方案:
- 调用
emplace传递临时对象,同样享受强制复制消除:std::optional<MyStruct> ms3; ms3.emplace(MyStruct{3}); - 结合
std::in_place和列表初始化:std::optional<MyStruct> ms4(std::in_place, MyStruct{4});
如果你的Clang版本支持C++20指派初始化,也可以写为更清晰的形式:
std::optional<MyStruct> ms(std::in_place, {.a = 3});
内容的提问来源于stack exchange,提问作者cptFracassa
相关产品推荐
相关产品推荐

