考虑以下MCVE:
#include <iostream>
int main()
{
void foo(int);
std::cout << foo << std::endl;
return 0;
}
这里我故意尝试以错误的方式打印指向函数的指针,以便选择接受bool
的{{3}}。
basic_ostream& operator<<( bool value );
让我感到困惑的是,operator<< overload和gcc 7.2都会产生警告,但编译并链接该程序。
同时, Visual Studio 15.5.6 不会链接此示例。
就我个人而言,我预计,尽管用作foo
的编译器似乎 ODR使用,但此代码根本不会链接。
有人可以解释为什么 gcc 和 clang 能够链接该程序吗?
答案 0 :(得分:7)
这是ODR违规行为。但根据[basic.def.odr]/10,强调我的:
每个程序都应包含每个非内联的一个定义 在a之外的程序中使用的函数或变量 废弃的陈述; 无需诊断。定义可以 在程序中明确出现,可以在标准中找到或者 用户定义的库,或(在适当的时候)它是隐式定义的 (参见[class.ctor],[class.dtor]和[class.copy])。内联函数 或变量应在其所在的每个翻译单元中定义 在废弃的陈述之外使用。
我们必须记住,编译器可以自由地假设您不会编写表现出不确定行为的代码,或者以他们不需要诊断的方式编写错误的代码。由于每个函数的地址都必须为空,因此只能使用bool
调用true
重载,因为转换必须在中生成的内容才有效程序
我们可以看到GCC 7.3这样做。即使在-O0
,即使在let searchController = UISearchController(searchResultsController: nil)
override func viewDidLoad() {
super.viewDidLoad()
searchController.searchResultsUpdater = self
searchController.obscuresBackgroundDuringPresentation = false
searchController.hidesNavigationBarDuringPresentation = false
definesPresentationContext = true
navigationItem.searchController = searchController
navigationItem.hidesSearchBarWhenScrolling = false
}
,它也会传递1作为转换的结果。