我知道至少有一个C ++ 11中的更改会导致一些旧代码停止编译:在标准库中引入explicit operator bool()
,替换operator void*()
的旧实例。当然,这将破坏的代码可能是首先不应该有效的代码,但它仍然是一个重大变化:过去不再有效的程序。
还有其他重大变化吗?
答案 0 :(得分:175)
FDIS有一个不兼容的部分,见附录C.2
“C ++和ISO C ++ 2003”。
总结,在这里解释FDIS,使其(更好)适合作为SO答案。我添加了一些我自己的例子来说明差异。
有一些与图书馆相关的不兼容性,我并不完全知道它的含义,所以我留给其他人详细说明。
#define u8 "abc"
const char *s = u8"def"; // Previously "abcdef", now "def"
#define _x "there"
"hello"_x // now a user-defined-string-literal. Previously, expanded _x .
新关键字:alignas,alignof,char16_t,char32_t,constexpr,decltype,noexcept,nullptr,static_assert和thread_local
某些大于long的整数文字可以用无符号整数类型改为有符号长整数。
使用整数除法的有效C ++ 2003代码将结果舍入为0或向负无穷大,而C ++ 0x始终将结果舍入为0。
(对大多数人来说,这不是一个真正的兼容性问题)。
使用关键字
auto
作为存储类说明符的有效C ++ 2003代码在C ++ 0x中可能无效。
缩小转换会导致与C ++ 03不兼容。例如,以下代码在C ++ 2003中有效,但在本国际标准中无效,因为double to int是一个缩小的转换:
int x[] = { 2.0 };
当隐式定义形成错误时,隐式声明的特殊成员函数被定义为已删除。
在不需要定义的上下文中(例如,在无法评估的表达式中)使用这些特殊成员函数之一的有效C ++ 2003程序变得格式不正确。
我的例子:
struct A { private: A(); };
struct B : A { };
int main() { sizeof B(); /* valid in C++03, invalid in C++0x */ }
一些SFINAE已经使用了这么大的技巧,现在需要改变:)
用户声明的析构函数具有隐式异常规范。
我的例子:
struct A {
~A() { throw "foo"; }
};
int main() { try { A a; } catch(...) { } }
此代码在C ++ 0x中调用terminate
,但在C ++ 03中不调用。因为C ++ 0x中A::~A
的隐式异常规范是noexcept(true)
。
包含
export
的有效C ++ 2003声明在C ++ 0x中格式不正确。
包含
>
并且紧跟另一个>
的有效C ++ 2003表达式现在可以被视为关闭两个模板。
在C ++ 03中,>>
始终是shift-operator标记。
允许具有内部链接的函数的依赖调用。
我的例子:
static void f(int) { }
void f(long) { }
template<typename T>
void g(T t) { f(t); }
int main() { g(0); }
在C ++ 03中,这会调用f(long)
,但在C ++ 0x中,这会调用f(int)
。应该注意的是,在C ++ 03和C ++ 0x中,以下调用f(B)
(实例化上下文仍然只考虑外部链接声明)。
struct B { };
struct A : B { };
template<typename T>
void g(T t) { f(t); }
static void f(A) { }
void f(B) { }
int main() { A a; g(a); }
没有采用更好的匹配f(A)
,因为它没有外部链接。
使用添加到C ++标准的任何标识符的有效C ++ 2003代码 C ++ 0x库可能无法编译或在本国际标准中产生不同的结果。
有效的C ++ 2003代码,在此国际标准中,
#includes
标题包含新C ++ 0x标准库标题的名称可能无效。
编译的有效C ++ 2003代码期望交换位于
<algorithm>
可能必须包含<utility>
全局命名空间
posix
现在保留用于标准化。
有效的C ++ 2003代码将
override
,final
,carries_dependency
或noreturn
定义为宏,在C ++ 0x中无效。
答案 1 :(得分:27)
auto关键字的含义已更改。
答案 2 :(得分:23)
突破变化?
嗯,首先,如果您使用decltype
,constexpr
,nullptr
等作为标识符,那么您可能会遇到麻烦......
答案 3 :(得分:22)
不兼容性部分未涵盖的一些核心不兼容性:
如果将名称作为参数传递给模板模板参数,则C ++ 0x会将注入的类名称视为模板,如果将其传递给模板类型参数,则将其视为类型。
如果有效的C ++ 03代码依赖于注入的类名在这些场景中始终是一种类型,则其行为可能会有所不同。示例代码taken from my 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
,从而导致冲突使用定义查找。
目前尚不清楚这是否是FDIS的缺陷。委员会意识到这一点,并将对情况进行评估。
使用声明,其中最后一部分与表示基类的限定名称中限定符的最后部分中的标识符相同,使用声明现在命名构造函数,而不是具有该名称的成员。
示例:
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
。
答案 4 :(得分:14)
流处理提取失败的处理方式不同。
#include <sstream>
#include <cassert>
int main()
{
std::stringstream ss;
ss << '!';
int x = -1;
assert(!(ss >> x)); // C++03 and C++11
assert(x == -1); // C++03
assert(x == 0); // C++11
}
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2011/n3246.html#23
之一
[C++03: 22.2.2.1.2/11]:
第2阶段处理的结果可以是
- 在阶段2中累积了一系列字符,这些字符被转换(根据
中scanf
的规则)到val
类型的值。此值存储在val
中,ios_base::goodbit
存储在err
。- 第2阶段累积的字符序列会导致
scanf
报告输入失败。ios_base::failbit
被分配到err
。 [ed:val
中没有存储任何内容。]
[C++11: 22.4.2.1.2/3]:
[..] 要存储的数值可以是以下值之一:
- 零,如果转换功能无法转换整个字段。
ios_base::failbit
被分配到err
。- 最正可表示的值,如果该字段表示的值太大而无法在
val
中表示。ios_base::failbit
被分配到err
。- 无效的可表示值或无符号整数类型的零,如果该字段表示的值太大而无法在
val
中表示。ios_base::failbit
被分配到err
。- 转换后的值,否则。
结果数值存储在
中val
。
GCC 4.8 correctly outputs for C++11:
断言`x == -1'失败
GCC 4.5-4.8 all output for C++03以下内容似乎是一个错误:
断言`x == -1'失败
Visual C ++ 2008 Express 正确输出C ++ 03:
断言失败:x == 0
Visual C ++ 2012 Express 错误地输出C ++ 11,这似乎是一个执行状态问题:
断言失败:x == 0
答案 5 :(得分:13)
如何引入显式转换运算符?旧版本仍将像以前一样“有效”。
是的,从operator void*() const
到explicit operator bool() const
的更改将是一个重大变化,但前提是它的使用方式本身就是错误的。符合规范的代码不会被破坏。
现在,另一个重大变化是the banning of narrowing conversions during aggregate initialization:
int a[] = { 1.0 }; // error
修改:记住,std::identity<T>
will be removed in C++0x(请参阅说明)。这是一种使类型依赖的便利结构。由于结构实际上没有做太多,这应该解决它:
template<class T>
struct identity{
typedef T type;
};
答案 6 :(得分:8)
对容器库进行了大量更改,这些更改允许更高效的代码,但在几个极端情况下默默地向后兼容。
例如,考虑std::vector
, default construction, C++0x, and breaking changes。
答案 7 :(得分:7)
对implicit move breaking backward compatibility
进行了大量讨论(an older page with relevant discussion)
如果你读到评论,隐含的移动返回也是一个突破性的变化。
答案 8 :(得分:6)
struct x {
x(int) {}
};
void f(auto x = 3) { }
int main() {
f();
}
C ++ 03:有效。
C ++ 0x: error: parameter declared 'auto'
答案 9 :(得分:-2)
>>