【问题标题】:Why implicit conversion of bool to string isn't an error?为什么布尔到字符串的隐式转换不是错误?
【发布时间】:2015-11-07 16:30:47
【问题描述】:

我盯着它并试图在 SO 上找到类似的问题,但没有发现任何有用的东西。所以,在这里发布我的问题。

考虑这个程序:

#include <iostream>
void foo(const std::string &) {}
int main() 
{
    foo(false);
}
[警告] 将 'false' 转换为 'std::basic_string::basic_string(const _CharT*, const _Alloc&) 的参数 1 的指针类型 [with _CharT = char; _Traits = std::char_traits; _Alloc = std::allocator]' [-Wconversion-null]

为什么 C++ 允许在没有显式转换的情况下这样做?我期待得到编译器错误。由于异常显示如下,程序在运行时异常终止:

terminate called after throwing an instance of 'std::logic_error'
  what():  basic_string::_S_construct null not valid

This application has requested the Runtime to terminate it in an unusual way.
Please contact the application's support team for more information.

标准对这种类型的隐式转换有何规定?

【问题讨论】:

  • “标准对这种类型的隐式转换有何规定?” 它说是允许的。
  • @Downvoters:为什么要投反对票?有什么问题?
  • 在 gcc 上,例如:melpon.org/wandbox/permlink/axWuSF1Nalk1Gr74。也许原因是 false 可以隐式转换为 const char* 作为空指针。
  • 您可以查看this
  • @PravasiMeet 我不是在谈论终止。我说的是编译。如果它编译,那么你应该期待一个异常终止,因为当你从空指针实例化一个字符串时会发生这种情况。

标签: c++ string boolean language-lawyer implicit-conversion


【解决方案1】:

bool 基本上是一个整数,因此它将被解释为零,在您的情况下,它可能是 0 字符,这将导致该问题字符串将异常

【讨论】:

    【解决方案2】:

    发生的情况是std::string 是从false 隐式构造的,使用const CharT* 重载并将false 转换为空指针。根据该构造函数的文档:

    如果s [指针] 未指向至少包含Traits::length(s)+1 元素的CharT 的数组,则行为未定义。

    因此出现故障(以友好异常的形式,但不要依赖它)。

    现在,正确吗?根据 [conv.ptr] :

    空指针常量是一个整数文字 (2.13.2),其值为 0 或类型为 std::nullptr_t 的纯右值。

    false 的值确实为零,但不是整数文字(它是布尔文字)。因此,std::string 的构造函数对CharT* 的隐式转换是非标准的。

    事实上,当 GCC 发出警告时,Clang 拒绝编译它。

    【讨论】:

    • 如果你指定-std=c++03,Clang 会编译它。这仅取决于特定编译器版本的默认方言。
    • @Potatoswatter 但是问题没有提到 C++03。在 C++11 及更高版本中,只有文字 0 可以转换为空指针。
    • @Quentin:你为什么说不依赖友好异常的形式?
    • @PravasiMeet 如果不满足 s 指向实际数组的要求,该标准不会定义任何行为。生成的程序可以不做任何事情、崩溃、抛出异常或其他任何事情。您的标准库实现者决定在这种情况下抛出异常,这在某种意义上很好(比破坏内存更好),但不能保证在其他实现上表现相同。我确实想知道为什么这是一个例外而不是断言。
    • @Quentin:好的。谢谢
    【解决方案3】:

    在 C++11 引入 nullptr 关键字之前,空指针有点小题大做。任何等于 0 的整数文字都足以作为空指针常量,false 符合要求。

    因此,您的程序的效果是使用char const * 参数NULL 构造std::string。构造函数不支持空指针,因此您会得到未定义的行为。

    解决此问题的方法是使用较新的 C++ 方言。如有必要,将-std=c++11 传递给编译器,或-std=c++14。然后你应该得到这样的东西:

    error: no matching function for call to 'foo'
    

    http://coliru.stacked-crooked.com/a/7f3048229a1d0e5a

    编辑: 嗯,GCC 似乎还没有实施此更改。这有点令人惊讶。你可以试试 Clang。

    我已经filed 一个错误报告。

    【讨论】:

    • GCC 仍然在启用 C++11 或 C++14 的情况下对其进行编译。
    • @Quentin,它会发出诊断,从技术上讲,这是格式错误的程序所需的全部内容。我宁愿这是一个错误而不是警告。
    • @JonathanWakely 但是 SFINAE 和重载偏序呢?我现在懒得用具体的例子来测试了,对不起。
    • @JonathanWakely 我撒了谎,没那么懒惰。 gcc.gnu.org/bugzilla/show_bug.cgi?id=67216
    • @PravasiMeet 实现可以免费提供扩展,为格式错误的程序赋予意义,因此 GCC 仍然符合要求。编辑:忘记这一点:Potatoswatter 的示例表明它确实是一个错误,因为它修改了格式良好程序的解释。
    猜你喜欢
    • 2015-10-03
    • 2017-11-09
    • 1970-01-01
    • 2018-02-11
    • 2019-09-02
    • 1970-01-01
    • 1970-01-01
    • 2016-02-27
    • 2011-01-22
    相关资源
    最近更新 更多