为啥 std::optional 构造函数使用 std::in_place?
Posted
技术标签:
【中文标题】为啥 std::optional 构造函数使用 std::in_place?【英文标题】:Why do std::optional constructors use std::in_place?为什么 std::optional 构造函数使用 std::in_place? 【发布时间】:2018-09-20 22:01:42 【问题描述】:一些std::optional
构造函数使用std::in_place_t
标记参数,如下所示:
template< class... Args >
explicit optional( std::in_place_t, Args&&... args );
我看到这样的构造函数可以在没有就地标记的情况下实现,并使用一些enable_if
(SFINAE) 魔法来不参与不情愿的重载,即:
template< class... Args >
explicit optional( Args&&... args );
为什么std::optional
的就地构造函数使用std::in_place_t
标签而不是一些enable_if
魔术(并且没有标签)实现?
更新:稍微更新了问题,以强调我意识到简单地省略就地标记是行不通的。
【问题讨论】:
匹配任何东西。 @Cheersandhth.-Alf 为什么这是个问题? 假设T
有一个隐式转换构造函数,它接受一个类型不等于T
的单个参数。然后,您将创建一个临时值,而不是将该值用于就地构造,而没有机会更改它。
@MatthäusBrandl 但你可以通过 SFINAE 来阻止这种情况。实际上,无论有无标签,都只转发一个参数。没有创建临时对象
据我所知,假设的无标签版本失败的唯一情况是默认构造包含的值
【参考方案1】:
正如Passer By 在comment 中所说,其目的是为了消除人们想要调用optional<T>
的默认构造函数和想要调用T
的默认构造函数的情况的歧义。
此意图在N3527 中提出,其中in_place_t
的原始建议名称为emplace
。我在这里引用相关部分:
我们需要额外的标签来消除某些情况的歧义,比如调用
optional
的默认构造函数和请求T
的默认构造函数:optional<Big> obemplace, "1"; // calls Big"1" in place (no moving) optional<Big> ocemplace; // calls Big in place (no moving) optional<Big> od; // creates a disengaged optional
【讨论】:
如何搜索论文/提案? @0x499602D2 我用关键字“C++ in_place_t paper”搜索,找到N3793,然后找到N3527。 @0x499602D2 如果您有权访问 CppLang Slack,您可以向 npaperbot 发送消息。真的很棒! @xskxzr 如果std::optional<T>
构造函数输入 2 个或更多参数,难道不能总是假设这些需要转发给 T's
构造函数,因此不需要 in_place_t
吗?
@user3882729 2 个或多个 args 的接口与 1 个 args 的接口不同,这很奇怪。以上是关于为啥 std::optional 构造函数使用 std::in_place?的主要内容,如果未能解决你的问题,请参考以下文章
为啥 std::optional<int> 的构造比 std::pair<int, bool> 更昂贵?
为啥 std::optional 对 std::nullopt 类型的操作数有一个特殊的相等运算符
为啥 std::optional::value() &&;返回 &&?
std::optional - 用 或 std::nullopt 构造空?
为啥允许将 std::optional 与值进行比较? [复制]
为啥 const rvalue 限定 std::optional::value() 返回 const rvalue 引用?