返回时不允许隐式转换

Implicit conversion not allowed on return

提问人:darune 提问时间:2/14/2020 最后编辑:darune 更新时间:4/12/2020 访问量:3794

问:

#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 语句;
  • 当表达式用于 switch 语句时(T2 是整数类型);
  • 当表达式用于 if 语句或循环时(T2 为 bool)。
C++ 语言律师 C++17 隐式转换

评论

7赞 Jarod42 2/14/2020
“执行隐式转换”,但运算符 bool()显式的。std::optional

答:

26赞 Sneftel 2/14/2020 #1

std::optional没有任何用于隐式转换为 的工具。(允许隐式转换通常被认为是一个坏主意,因为这是一个整数类型,所以类似的东西会编译并做完全错误的事情。boolboolboolint i = opt

std::optional 确实有一个到 bool 的“上下文转换”,其定义看起来类似于强制转换运算符:.这不能用于隐式转换;它仅适用于预期的“上下文”为布尔值的某些特定情况,例如 if 语句的条件。explicit operator bool()

你想要的是.opt.has_value()

5赞 NutCracker 2/14/2020 #2

来自 C++ 文档

当 optional 类型的对象< T > 在上下文中转换为 bool 时, 如果对象包含值,则转换返回 true,如果对象包含值,则返回 false 如果它不包含值。

在此处阅读有关内容相关转化的信息:

在以下上下文中,类型 bool 是预期的,隐式 如果声明 bool t(e);结构良好 (即显式转换函数,例如显式 T::运算符 bool() 常量;被考虑)。这种表达式 e 被称为 在上下文中转换为布尔值。

  • if、while、for 的控制表达式;
  • 内置逻辑运算符 !、&& 和 ||;
  • 条件运算符的第一个操作数 ?:;
  • static_assert声明中的谓语;
  • noexcept 说明符中的表达式;
  • 显式说明符中的表达式;

您可以执行以下操作:

bool f() {
    std::optional<int> opt;
    return opt || false;
}

因为上下文转换发生在内置逻辑运算符的情况下,但上下文转换不包括语句,并且本身没有隐式转换为 .returnstd::optionalbool

因此,最好使用 std::optional<T>::has_value:

bool f() {
    std::optional<int> opt;
    return opt.has_value();
}

评论

0赞 darune 2/14/2020
怎么样?或return {opt}return bool{opt};
3赞 NutCracker 2/14/2020
@darune行不通,但或会行得通。但是,建议使用成员函数,因为它确实显示了您想要执行的操作的明确意图return {opt};return static_cast<bool>(opt);return bool{opt};has_value
0赞 L. F. 2/25/2020
或者著名的黑客(更好)return !!pot;has_value
1赞 theWiseBro 2/14/2020 #3

这是因为不支持将 std::optional 隐式转换为 bool:https://en.cppreference.com/w/cpp/utility/optional/operator_bool

constexpr 显式运算符 bool() const noexcept;

您必须显式转换为 bool as 或简单地改用。bool(opt)opt.has_value()

评论

0赞 darune 2/14/2020
bool{opt} 也有效,应该优先于 bool(opt)
1赞 Trixie 4/12/2020 #4

这并不是关于隐式转换,而是关于初始化的类型。

可选的是一个显式的转换函数,即

explicit operator bool() const; 

从 N4849 [class.conv.fct]/p2

转换函数可以是显式的 (9.2.2),在这种情况下,它仅被视为用户定义的转换 用于直接初始化。

以上意味着这些情况会使用转换函数: [dcl.init]/p16

发生的初始化 (16.1) - 对于作为括号的表达式列表或支撑初始化列表的初始值设定项, (16.2) — 对于 new-initializer (7.6.2.7), (16.3) — 在static_cast表达式 (7.6.1.8) 中, (16.4) — 在函数表示法类型转换 (7.6.1.3) 中,以及 (16.5) — 在条件的 braced-init-list 形式中,称为直接初始化。

但是,这些情况不会使用转换函数: [dcl.init]/p15

以 = 形式发生的初始化 brace-or-equal-initializer 或条件 (8.5) 以及参数 传递、函数返回、抛出异常 (14.2)、处理 异常 (14.4) 和成员初始化 (9.4.1) 称为 复制初始化。

问题中的示例属于复制初始化情况,不使用 optional 的转换函数。