为什么 std::string 没有隐式转换为 bool

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 的 classes 很难保持安全。特别是,在许多您几乎不希望发生的情况下,这种转换可能(并且将会)发生。例如,如果我们假设 std::string 转换为 false 如果为空,否则转换为 true,那么您可以使用 string 本质上 anywhere 一个整数或指针。

编译器不会告诉您类型不匹配,而是会将字符串转换为布尔值,然后将布尔值转换为整数(假 -> 0,真 -> 1)。

像这样的事情经常发生,许多早期的字符串类型尝试(并且有 很多 )委员会显然决定最好将隐式转换保持在绝对最低限度(因此 string 支持的唯一隐式转换是从 C 风格字符串创建字符串对象)。

设计了多种方法来更安全地处理到 bool 的转换。一个是转换为 void *,这可以防止一些问题,但不能防止其他问题(这被 iostreams 使用)。还有一个 "safe bool" 成语(实际上,更像是一个 "safe bool" 主题,其中有几个变体)。虽然这些确实改进了对允许和不允许的转换的控制,但它们中的大多数都涉及相当多的开销(典型的安全 bool 需要约 50 行代码的基础 class,加上从该基础派生class,等等)

至于显式转换和上下文转换有何帮助,基本思路非常简单。您可以(从 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 语句的东西中,因此使用 class使用上面的转换函数,你会得到:

X x;
if (x) // allowed

int y = x; // would require explicit cast to compile

我要补充一点,关于 "orthogonality" 的抱怨在这里似乎很不适用。尽管方便,但将字符串转换为布尔值并没有多大意义。如果有的话,我们应该抱怨 string("0") 转换为 1 是多么奇怪(在发生这种情况的语言中)。

This article 提到了 operator bool() 可以导致令人惊讶的结果的一些原因。

请注意 std::string 只是 std::basic_string<char> 的类型定义。还有 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 风格的字符串共存。

根据定义 "a contiguous sequence of characters terminated by and including the first null character",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.

更快

如果有人发现用 C++ 实现 if (s) 的方法,请告诉我们。