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

时间:2015-01-30 00:00:07

标签: c++ string casting boolean

有没有理由说c ++ std::string没有隐式转换为bool?例如

std::string s = ""
if (s) { /* s in not empty */ }

和其他语言一样(例如python)。我认为使用empty方法很繁琐。

4 个答案:

答案 0 :(得分:22)

在C ++ 11添加了显式转换和上下文转换的概念之后,可能会添加

设计std::string时,这些都不存在。这使得支持转换为bool的类很难保持安全。特别是,这种转换可能(并且会发生)在许多你几乎从未想过的情况下发生。例如,如果我们假设std::string转换为false,如果为空,则转换为true,那么您可以使用string本质上任何地方整数或者是指针。

编译器不会告诉你类型不匹配,而是将字符串转换为bool,然后将bool转换为整数(false - > 0,true - > 1)。

这样的事情经常发生,很多早期的字符串类型尝试(并且有很多),委员会显然认为最好将隐式转换保持在绝对最小值(所以仅限于此string支持的隐式转换是从C风格的字符串创建一个字符串对象。)

为了更安全地处理转换为bool,设计了许多方法。一个是转换为void *,这可以防止一些问题,但不会转换为其他问题(iostreams会使用它)。还有一个“安全的bool”成语(实际上,更像是一个“安全的bool”主题,其中有几个变体)。虽然这些肯定会改进对转换将允许和不允许的转换的控制,但是大多数转换涉及相当大的开销(典型的安全bool需要大约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(在发生这种情况的语言中)有多奇怪。

答案 1 :(得分:9)

This article提到了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";
}

答案 2 :(得分:4)

std::string仍然必须与C风格的字符串共存。

C样式字符串按照定义&#34;由第一个空字符&#34;终止并包含第一个空字符&#34;的连续字符序列,通常通过指向其第一个字符的指针访问。在大多数情况下,诸如"hello, world"之类的表达式被隐式转换为指向第一个字符的指针。然后可以将这样的指针隐式转换为bool,如果指针为非空,则产生true,如果指针为空,则产生false。 (在C中,它没有转换为bool,但它仍然可以直接用作条件,因此效果几乎相同。)

所以,由于C ++的C传承,如果你写:

if ("") { ... }

空字符串已被视为true,并且在不破坏C兼容性的情况下无法轻松更改。

我建议将C风格的空字符串评估为true,将C ++空std::string评估为false会让人感到困惑。

if (!s.empty())

答案 3 :(得分:2)

我能找到的与你(和我)想要的最接近的是以下内容。

您可以在!上定义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)的方法,请告诉我们。