【发布时间】:2015-01-22 08:55:27
【问题描述】:
在将项目从 Visual Studio 2005 移植到 2013 时,我遇到了这种我无法找到解释的奇怪行为。上下文是关于通过多次包含某个头文件来创建模板特化,但在每次包含之前更改预处理器定义以基本上生成不同的类声明。
我可以将问题缩小到以下情况:
gen.hpp
#ifdef ENABLE_GEN
#ifdef GEN_SWAP_ORDER // (1)
class Foo {};
#else
class Bar {};
#endif
#endif
main.cpp
#define ENABLE_GEN
#include "gen.hpp"
#define GEN_SWAP_ORDER
#include "gen.hpp"
int main()
{
Foo foo;
Bar bar;
}
这按预期工作,即 Foo 和 Bar 在 main() 中声明和使用。
现在,要引起该问题,请将 (1) 标记的行中的 #ifdef 更改为 #ifndef,这实际上只会导致声明 Foo 和 Bar 的顺序被交换。但相反,编译会失败:
1>c:\path\to\main.cpp(10): error C2065: 'Bar' : undeclared identifier
1>c:\path\to\main.cpp(10): error C2146: syntax error : missing ';' before identifier 'bar'
1>c:\path\to\main.cpp(10): error C2065: 'bar' : undeclared identifier
预处理后的文件如下所示(去掉了一些空格):
#line 1 "c:\\path\\to\\main.cpp"
#line 1 "c:\\path\\to\\gen.hpp"
class Foo {};
#line 8 "c:\\path\\to\\gen.hpp"
#line 10 "c:\\path\\to\\gen.hpp"
#line 4 "c:\\path\\to\\main.cpp"
int main()
{
Foo foo;
Bar bar;
}
我的问题是:我错过了什么吗?这是出于某种原因的预期行为吗?是否是编译器设置/错误使 Visual Studio 在认为它具有标头保护时(因为 #ifndef)第二次跳过标头内容(包括 #else 部分)?
谢谢!
【问题讨论】:
-
即使您进行完全清理 + 重建(以排除预编译的标头恶作剧)也会发生这种情况吗?
-
Visual Studio 包含对包含保护的优化,也许它们有问题?有一个类似的预发布错误:connect.microsoft.com/VisualStudio/feedback/details/800200/…
-
Zinger,他们没有完全修复这个错误。使用 /showIncludes 可见,您将看到该文件仅获得 #included 一次。
-
我无法使用 Visual C++ 2013 RTM (18.00.21005.01) 或 Update 3 (18.00.30723.00) 重现此问题。
-
我很抱歉;我误读了您的问题,但没有注意到我需要将
#ifdef更改为#ifndef以重现问题。我重新激活了 Connect 错误并通知了我们的编译器团队。感谢您提请我们注意。
标签: c++ visual-c++ visual-studio-2013 c-preprocessor