众所周知,GCC 比 Visual C++ 更严格地实现 C++ 标准。
坦率地说,Visual C++ 只是没有很好地遵循 C++ 标准。
对于主要使用 Visual C++ 进行开发但需要至少使用 GCC 来移植和编译代码的开发人员来说,这一直是个令人头疼的问题。
一些 Visual C++ 语言不当行为记录在 MSDN Nonstandard Behavior topic 中实际上还有很多其他未记录的案例。
这篇文章的目的是记录 VC++ 与 GCC(最流行的 C++ 编译器)的所有已知兼容性问题。当使用 Visual C++ 编译某些代码片段时没有警告(W4 级别)并且不使用 GCC(产生错误或警告)时会引发问题。
请注意,它仅适用于标准 C++ 问题,Microsoft 特定语言扩展如 __super
或 __forceinline
超出范围。
建议的问题描述格式:
- 代码片段(使用 Visual C++ 编译成功)
- 它产生的 GCC 错误或警告
- 要重现的两个编译器版本
- 对违反 C++ 标准声明的引用(可选,可以稍后添加)
- 解决方案(如何修改代码才能被VC++和GCC成功编译)
这是一个相当宽泛的问题,但这里有一些我遇到过的事情:
错误的声明点:
#include <iostream>
struct S {
S(int) { std::cout << "Incorrect\n"; }
S(S const &) { std::cout << "Correct\n"; }
};
int s;
int main() {
S s(s);
}
输出应该是“正确的”,但 Visual Studio(所有版本)的输出是“不正确的”。
复制分配和复制初始化的生成不正确:
#include <iostream>
struct B {
B &operator = (B &) { std::cout << "Correct\n"; return *this; }
template<typename T>
B &operator = (T &) { std::cout << "Incorrect\n"; return *this; }
};
struct D : B {};
int main() {
D d;
d = d;
}
我认为这是在 Visual Studio 2012 中修复的。 2012 年之前 VS 的输出是“不正确的”。
两阶段名称查找:
#include <iostream>
static void foo(long) {
std::cout << "Correct\n";
}
template<typename T>
void bar(T t) {
foo(t);
}
static void foo(int) {
std::cout << "Incorrect\n";
}
int main() {
bar(1);
}
输出应该是“正确的”,但 Visual Studio(目前所有版本)的输出是“不正确的”。
替代 token 不起作用:
int main() <% %>
此程序应该可以编译并运行,但没有任何版本的 Visual Studio 可以成功编译它。
for 循环初始化器子句中的用户定义类型定义:
int main() {
for (struct {int a;} a = {0}; a.a < 10; ++(a.a)) {
}
}
这是合法的,但 VS 不允许。
所有这些都可以在 gcc 和 clang 下正确编译和运行,可以追溯到很多版本。 Gcc 曾经在两阶段查找方面存在问题,但现在暂时没有了。