为什么GCC 4.9.2中cout<"Yes"缺少左移运算符仍可正常编译?
GCC 4.9.2版本下流操作符漏写的异常编译问题
问题复现
如下漏写一个<的流输出代码,在GCC 4.9.2下可以正常编译,但运行时无任何输出,其他符合标准的编译器会直接抛出编译错误:
#include<iostream> using namespace std; int main(){ cout<"Yes"; }
对比语法正确的输出代码:
#include<iostream> using namespace std; int main(){ cout<<"Yes"; }
按照C++语法预期,漏写操作符的代码应该抛出类似如下的编译错误:
[Error] no match for 'operator<' (operand types are 'std::ostream {aka std::basic_ostream
}' and 'const char [4]')
同类异常编译场景还包括cin漏写>的情况,同样可以正常编译:
#include<iostream> using namespace std; int main(){ cin>"Yes"; }
就算使用全限定名、开启编译器所有警告,该问题仍然可以复现,无任何告警:
#include<iostream> int main(){ std::cout<"Yes"; }
原因说明
该问题是GCC 4.9.x版本对标准流的类型转换实现特性导致的:
- C++98标准中,
std::ostream、std::istream这类流对象为了支持if(cout)、if(cin)这类流状态判断逻辑,提供了**隐式转换到void***的成员函数,只要流处于正常状态就会返回非空指针。 - 代码中的字符串字面量
"Yes"在表达式中会自动退化为const char*类型的指针。 - 当编译器解析
cout < "Yes"时,没有找到匹配的operator<重载,就会触发隐式转换:将cout转为void*,字符串字面量转为const char*,两种指针类型原生支持大小比较运算,因此编译不会报错。 - 该表达式实际执行的是两个内存地址的大小比较,返回的布尔值没有被使用,因此运行时不会有任何输出,也不会触发运行时错误。
- 后续GCC版本遵循C++11标准要求,将流的状态转换函数改为
explicit operator bool(),禁止了隐式转换为指针的行为,因此高版本GCC和其他符合标准的编译器都会正确抛出找不到operator<的编译错误。
内容的提问来源于stack exchange,提问作者Miao Wang
相关产品推荐
相关产品推荐

