5

给定以下代码片段:

#include <string>
#include <iostream>

int main()
{
    std::string prefix("->"), middle(), suffix("<-");
    std::cout << "Test: " << prefix << middle << suffix << std::endl;

    return 0;
}

高级 C++ 程序员会立即看到,middle()它不是在调用std::string的默认 ctor,而是一个函数声明。

不过有趣的是:为什么 gcc 会产生以下输出:

Test: ->1<-

与 Visual Studio 的链接器错误相比?有人知道这里发生了什么吗?

4

2 回答 2

7

bool使用 with 时,函数指针将被转换为cout

为什么函数指针没有被隐式转换为a void *,这就是运算符<<重载的原因?因为函数指针不是对象指针。

C++11 §4.10/2:

“指向 cv T 的指针”类型的纯右值,其中 T 是对象类型,可以转换为“指向 cv void 的指针”类型的纯右值。将“指向 cv T 的指针”转换为“指向 cv void 的指针”的结果指向类型 T 的对象所在的存储位置的开始,就好像该对象是类型 T 的最派生对象 (1.8) (即,不是基类子对象)。空指针值转换为目标类型的空指针值。

于 2013-08-03T01:06:58.820 回答
1

正如 Yu 所说,函数指针正在转换为bool.

g++优化器显然是在预评估转换,而Visual C++实际上生成代码来测试函数地址是否为空,这需要链接器提供函数地址。

规则是

每个程序都应包含该程序中 odr 使用的每个非内联函数或变量的准确定义;无需诊断。

该函数odr-used 因为您正在使用它的地址。如果不提供定义,则违反了此规则,并且标准不需要诊断,这意味着工具链可以自由地做任何事情。

Visual C++ 正在生成诊断,尽管它不是必需的。

g++ 给出了转换为 的实际结果bool,因为它知道实际函数衰减为函数指针永远不会产生空函数指针。

但是格式化您的硬盘驱动器同样有效,因为标准没有说明工具链在这里可以做什么或不能做什么。

于 2013-08-03T01:15:45.407 回答