为什么 std::string 没有隐式转换为布尔值
why std::string is not implicitly converted to bool
c++ 中,std::string
没有隐式转换为布尔值的原因吗?例如
std::string s = ""
if (s) { /* s in not empty */ }
与其他语言一样(例如 Python)。我认为使用empty
方法很乏味。
现在 C++11 添加了显式转换和上下文转换的概念,因此可以添加这一点。
当std::string
被设计时,这些都不存在。这使得支持转换为bool
类相当难以保证安全。特别是,这种转换可能(并且会)在很多情况下发生,你几乎不希望它发生。例如,如果我们假设std::string
转换为 false
如果为空,否则转换为 true
,那么你基本上可以在任何需要整数或指针的地方使用 string
。
编译器不会告诉您类型不匹配,而是将字符串转换为布尔值,然后将布尔值转换为整数(false -> 0,true -> 1)。
像这样的事情经常发生,有很多早期的字符串类型尝试(而且有很多),委员会显然决定最好将隐式转换保持在绝对最小值(因此string
支持的唯一隐式转换是从 C 样式字符串创建字符串对象)。
设计了许多方法来更安全地处理转换为布尔值的方法。一种是转换为void *
,这可以防止一些问题,但不能防止其他问题(iostreams使用)。还有一个"安全布尔"成语(实际上,更像是一个"安全布尔"主题,其中有几个变体)。虽然这些肯定改善了对允许和不允许的转换的控制,但其中大多数都涉及相当多的开销(典型的安全布尔值需要~50行代码的基类,以及从该基类派生等)。
至于显式转换和上下文转换将如何提供帮助,基本思想非常简单。您可以(从 C++11 开始)将转换函数标记为 explicit
,这允许仅在使用显式强制转换为目标类型的情况下使用它:
struct X {
explicit operator bool() { return true; }
};
int main() {
X x;
bool b1 = static_cast<bool>(x); // compiles
bool b2 = x; // won't compile
}
上下文转换增加了一点,让转换为 bool 隐式发生,但仅限于像 if
语句这样的东西,所以使用带有上述转换函数的类,你会得到:
X x;
if (x) // allowed
int y = x; // would require explicit cast to compile
我想补充一点,关于"正交性"的抱怨在这里似乎很不适用。虽然方便,但将字符串转换为布尔值并没有多大意义。如果有的话,我们应该抱怨string("0")
转换为1
是多么奇怪(在发生这种情况的语言中)。
本文提到了operator bool()
会导致令人惊讶的结果的一些原因。
请注意,std::string
只是 std::basic_string<char>
的 typedef 。多字节字符也有std::wstring
。隐式转换可以让你写:
std::string foo = "foo";
std::wstring bar = "bar";
if (foo == bar) {
std::cout << "This will be printed, because both are true!n";
}
std::string
仍然必须与 C 样式的字符串共存。
根据定义,C 样式字符串是"以第一个空字符结尾并包括第一个空字符的连续字符序列",通常通过指向其第一个字符的指针进行访问。在大多数情况下,"hello, world"
等表达式隐式转换为指向第一个字符的指针。然后,这样的指针可以隐式转换为bool
,如果指针为非空,则产生true
,如果指针为空,则false
为空。(在 C 中,它没有转换为 bool
,但它仍然可以直接用作条件,因此效果几乎相同。
因此,由于C++的C遗产,如果您写道:
if ("") { ... }
空字符串已经被视为true
,并且如果不破坏C兼容性,就无法轻易更改。
我建议将 C 样式的空字符串评估为 true
,将C++空字符串std::string
评估为 false
会太混乱了。
写if (!s.empty())
并不难(恕我直言,它更清晰)。
我能够找到的最接近你(和我)想要的东西是以下内容。
您可以在std::string's
上定义 !
运算符,如下所示:
bool operator!(const std::string& s)
{
return s.empty();
}
这允许您执行以下操作:
std::string s;
if (!s) // if `s` is empty
使用简单的否定,您可以执行以下操作:
if (!!s) // if `s` is not empty
这有点尴尬,但问题是,你有多想避免额外的字符? !strcmp(...)
也很尴尬,但我们仍然起作用并习惯了它,我们中的许多人更喜欢它,因为它比打字strcmp(...) == 0
快。
如果有人发现了一种方法来做if (s)
,C++,请告诉我们。
- 变量定义到C++布尔值转换
- fstream / ifstream / ofstream 对象如何转换为布尔值
- 将uintptr_t转换为布尔值会使 SSO 基准速度减慢数倍
- 在目标 c++ 中将 CFTypeRef 转换为布尔值
- isspace 函数的性能警告,从 int 转换为布尔值
- 将返回表达式隐式转换为布尔值
- 将结构转换为布尔值
- 整数在 C++ 中没有被类型转换为布尔值
- 为什么我的变体将 std::string 转换为布尔值
- 为什么使用 int 的转换,而不是布尔值
- lambda 转换为布尔值,而不是推导函数指针类型
- 从常量字符串到布尔值的隐式强制转换
- 我无法将'2D array whit bool'转换为"空 2D 数组布尔值"(用于生命游戏)
- 尝试将字符串变量转换为布尔值会导致 "true" 和 "false" 都等于 0
- Typedef shared_ptr转换为<T>布尔值
- 如果模板值可转换为布尔值,则在编译时禁用类方法
- 避免或警告在 GCC 中从常量字符* 隐式转换为布尔值
- 为什么 lambda 会转换为值为真的布尔值?
- 有没有办法将模板的替换失败转换为布尔值(真/假)或标签(标准::true_type/标准::false_type)
- 将流隐式转换为布尔值