我知道c++ 11中至少有一个变化会导致一些旧代码停止编译:在标准库中引入显式操作符bool(),取代操作符void*()的旧实例。当然,这将破坏的代码可能是本来就不应该有效的代码,但它仍然是一个破坏性的更改:过去有效的程序不再有效。
还有其他重大变化吗?
我知道c++ 11中至少有一个变化会导致一些旧代码停止编译:在标准库中引入显式操作符bool(),取代操作符void*()的旧实例。当然,这将破坏的代码可能是本来就不应该有效的代码,但它仍然是一个破坏性的更改:过去有效的程序不再有效。
还有其他重大变化吗?
当前回答
有很多关于隐式移动破坏向后兼容性的讨论
(有相关讨论的旧页)
如果你向下阅读注释,隐式move return也是一个突破性的变化。
其他回答
对容器库进行了大量更改,可以实现更高效的代码,但在一些极端情况下会默默地破坏向后兼容性。
例如,考虑std::vector、默认结构、c++ 0x和破坏性更改。
显式转换运算符的引入如何成为突破性的变化?旧版本仍然和以前一样“有效”。
是的,从操作符void*() const到显式操作符bool() const的变化将是一个破坏性的变化,但前提是它的使用方式内外都是错误的。符合规范的代码不会被打破。
现在,另一个突破性的变化是在聚合初始化期间禁止收缩转换:
int a[] = { 1.0 }; // error
编辑:请记住,std::identity<T>将在c++ 0x中被删除(参见注释)。它是一种方便的结构体,可以使类型相互依赖。由于结构体实际上并没有做太多的事情,这应该可以修复它:
template<class T>
struct identity{
typedef T type;
};
断改变?
嗯,首先,如果你使用decltype, constexpr, nullptr等作为标识符,那么你可能会遇到麻烦……
auto关键字的含义改变。
一些核心不兼容性在不兼容性部分中没有涉及:
c++ 0x将注入的类名作为模板模板形参的实参传递,将类名作为类型传递给模板类型形参。
如果在这些场景中,有效的c++ 03代码依赖于注入的类名始终是类型,那么它的行为可能会有所不同。示例代码从我的clang PR
template<template<typename> class X>
struct M { };
template<template<typename> class X>
void g(int = 0); // #1
template<typename T>
void g(long = 0); // #2
template<typename T>
struct A {
void f() {
g<A>(); /* is ambiguous in C++0x */
g<A>(1); /* should choose #1 in C++0x */
}
};
void h() {
A<int> a;
a.f();
}
在c++ 03中,代码两次调用第二个g。
c++ 0x将c++ 03中依赖的一些名称改为非依赖名称。并且需要查找在实例化时重复引用当前类模板成员的非依赖限定名,并且需要验证这些名称的查找方式是否与模板定义上下文中的查找方式相同。
由于此更改,依赖支配性规则的有效c++ 03代码现在可能无法再编译。
例子:
struct B { void f(); };
template<typename T>
struct A : virtual B { void f(); };
template<typename T>
struct C : virtual B, A<T> {
void g() { this->f(); }
};
int main() { C<int> c; c.g(); }
这个调用A<int>::f的有效c++ 03代码在c++ 0x中无效,因为实例化时的名称查找将找到A<int>::f而不是B::f,导致与at-definition查找冲突。
在这一点上,还不清楚这是否是FDIS的缺陷。委员会意识到这一点,并将对情况进行评估。
using声明的最后一部分与表示基类的限定名中的限定符的最后一部分中的标识符相同,该using声明现在命名构造函数,而不是具有该名称的成员。
例子:
struct A { protected: int B; };
typedef A B;
struct C : B {
// inheriting constructor, instead of bringing A::B into scope
using B::B;
};
int main() { C c; c.B = 0; }
上面的示例代码在c++ 03中格式良好,但在c++ 0x中格式不佳,因为A::B在main中仍然不可访问。