#include <optional>
bool f() {
std::optional<int> opt;
return opt;
}
不编译:'return': cannot convert from 'std::optional<int>' to 'bool'
咨询参考 我本来想找到一个解释,但我读了它,因为它应该没问题。
每当某种类型的表达式时,都会执行隐式转换 T1 用于不接受该类型但接受某些类型的上下文 其他T2型;特别:
- 当调用以 T2 作为参数声明的函数时,表达式用作参数;
- 当表达式用作具有期望 T2 的运算符的操作数时;
初始化 T2- 类型的新对象时,包括返回 T2 的函数中的 return 语句;
- 当表达式用于开关语句时(T2 是整型(;
- 当表达式用于 if 语句或循环时(T2 是布尔值(。
std::optional
没有任何隐式转换为bool
的工具。(允许隐式转换为bool
通常被认为是一个坏主意,因为bool
是一个整数类型,所以像int i = opt
这样的东西会编译并做完全错误的事情。
std::optional
确实有一个到 bool 的"上下文转换",其定义看起来类似于强制转换运算符:explicit operator bool()
。这不能用于隐式转换;它仅适用于预期的"上下文"是布尔值的某些特定情况,例如 if 语句的条件。
你想要的是opt.has_value()
.
来自C++文档:
当optional
类型的对象在上下文中转换为布尔值时, 如果对象包含值,则转换返回 true,如果对象包含值,则返回 false 如果它不包含值。
在此处阅读有关内容相关转化的信息:
在以下上下文中,类型布尔是预期的,隐式 如果声明布尔值 t(e(,则执行转换;格式良好 (即显式转换函数,例如显式 T::运算符 bool(( const;被考虑(。这样的表达式 e 被称为 上下文转换为布尔值。
- 如果、而、为的控制表达式;
- 内置逻辑运算符的操作数 !, && 和 ||;
- 条件运算符的第一个操作数 ?:;
- static_assert声明中的谓词;
- 不分说明符中的表达式;
- 显式说明符中的表达式;
您可以执行以下技巧:
bool f() {
std::optional<int> opt;
return opt || false;
}
因为上下文转换发生在内置逻辑运算符的情况下,但上下文转换不包括return
语句,并且std::optional
本身没有隐式转换为bool
。
因此,最好使用以下std::optional<T>::has_value
:
bool f() {
std::optional<int> opt;
return opt.has_value();
}
这是因为不支持将 std::optional 隐式转换到布尔: https://en.cppreference.com/w/cpp/utility/optional/operator_bool
constexpr explicit operator bool(( const noexcept;
您必须显式转换为 bool 作为bool(opt)
或干脆使用opt.has_value()
代替。
这不是真正的隐式转换,这是关于初始化的类型。
可选的是显式转换函数,即
explicit operator bool() const;
从 N4849 [class.conv.fct]/p2
转换函数可能是显式的 (9.2.2(,在这种情况下,它仅被视为用户定义的转换 用于直接初始化。
以上意味着这些情况将使用转换函数: [dcl.init]/p16
发生的初始化 (16.1( — 对于作为括号表达式列表或大括号初始化列表的初始值设定项, (16.2( — 对于新初始值设定项 (7.6.2.7(, (16.3( — 在static_cast表达式 (7.6.1.8( 中, (16.4( — 在函数表示法类型转换 (7.6.1.3( 中,以及 (16.5( — 在条件的大括号初始化列表形式中称为直接初始化。
但是,这些情况不会使用转换函数: [dcl.init]/p15
以 = 形式发生的初始化 大括号或等于初始值设定项或条件 (8.5(,以及参数 传递、函数返回、引发异常 (14.2(、处理 异常 (14.4( 和成员初始化 (9.4.1( 称为 复制初始化。
问题中的示例属于复制初始化情况,不使用可选的转换函数。