本文翻译自:Can C++ code be valid in both C++03 and C++11 but do different things?
C ++代码是否可以符合C ++ 03标准和C ++ 11标准,但根据编译的标准,可以做不同的事情吗?
#1楼
参考:https://stackoom.com/question/1Yhd0/C-代码可以在C-和C-中有效但是做不同的事情吗
#2楼
I point you to this article and the follow-up , which has a nice example of how >>
can change meaning from C++03 to C++11 while still compiling in both. 我点你这篇文章和随访 ,其中有如何一个很好的例子>>
可以改变从C ++ 03意为C ++ 11,而在静止编制。
bool const one = true;
int const two = 2;
int const three = 3;
template<int> struct fun {
typedef int two;
};
template<class T> struct fon {
static int const three = ::three;
static bool const one = ::one;
};
int main(void) {
fon< fun< 1 >>::three >::two >::one; // valid for both
}
The key part is the line in main
, which is an expression. 关键部分是main
的一行,它是一个表达式。
In C++03: 在C ++ 03中:
1 >> ::three = 0
=> fon< fun< 0 >::two >::one;
fun< 0 >::two = int
=> fon< int >::one
fon< int >::one = true
=> true
In C++11 在C ++ 11中
fun< 1 > is a type argument to fon
fon< fun<1> >::three = 3
=> 3 > ::two > ::one
::two is 2 and ::one is 1
=> 3 > 2 > 1
=> (3 > 2) > 1
=> true > 1
=> 1 > 1
=> false
Congratulations, two different results for the same expression. 恭喜,同一表达的两个不同结果。 Granted, the C++03 one did come up with a warning form Clang when I tested it. 当然,在我测试它时,C ++ 03确实提出了警告形式Clang。
#3楼
The answer is a definite yes. 答案肯定是肯定的。 On the plus side there is: 从好的方面来说,有:
- Code that previously implicitly copied objects will now implicitly move them when possible. 以前隐式复制对象的代码现在将隐式移动它们。
On the negative side, several examples are listed in the appendix C of the standard. 从消极方面来看,标准的附录C中列出了几个例子。 Even though there are many more negative ones than positive, each one of them is much less likely to occur. 即使有更多的负面因素而不是正面,每一个都不太可能发生。
String literals 字符串文字
#define u8 "abc"
const char* s = u8"def"; // Previously "abcdef", now "def"
and 和
#define _x "there"
"hello "_x // Previously "hello there", now a user defined string literal
Type conversions of 0 输入0的转化次数
In C++11, only literals are integer null pointer constants: 在C ++ 11中,只有文字是整数空指针常量:
void f(void *); // #1
void f(...); // #2
template<int N> void g() {
f(0*N); // Calls #2; used to call #1
}
Rounded results after integer division and modulo 整数除法和模数后的舍入结果
In C++03 the compiler was allowed to either round towards 0 or towards negative infinity. 在C ++ 03中,允许编译器向0或向负无穷大舍入。 In C++11 it is mandatory to round towards 0 在C ++ 11中,必须向0舍入
int i = (-1) / 2; // Might have been -1 in C++03, is now ensured to be 0
Whitespaces between nested template closing braces >> vs > > 嵌套模板关闭括号>> vs >>之间的空格
Inside an specialization or instantiation the >>
might instead be interpreted as an right-shift in C++03. 在专门化或实例化中, >>
可能会被解释为C ++ 03中的右移。 This is more likely to break existing code though: (from http://gustedt.wordpress.com/2013/12/15/a-disimprovement-observed-from-the-outside-right-angle-brackets/ ) 这更有可能破坏现有代码:(来自http://gustedt.wordpress.com/2013/12/15/a-disimprovement-observed-from-the-outside-right-angle-brackets/ )
template< unsigned len > unsigned int fun(unsigned int x);
typedef unsigned int (*fun_t)(unsigned int);
template< fun_t f > unsigned int fon(unsigned int x);
void total(void) {
// fon<fun<9> >(1) >> 2 in both standards
unsigned int A = fon< fun< 9 > >(1) >>(2);
// fon<fun<4> >(2) in C++03
// Compile time error in C++11
unsigned int B = fon< fun< 9 >>(1) > >(2);
}
Operator new
may now throw other exceptions than std::bad_alloc
operator new
现在可能抛出除std::bad_alloc
之外的其他异常
struct foo { void *operator new(size_t x){ throw std::exception(); } }
try {
foo *f = new foo();
} catch (std::bad_alloc &) {
// c++03 code
} catch (std::exception &) {
// c++11 code
}
User-declared destructors have an implicit exception specification example from What breaking changes are introduced in C++11? 用户声明的析构函数有一个隐式异常规范示例来自C ++ 11中引入了哪些重大更改?
struct A {
~A() { throw "foo"; } // Calls std::terminate in C++11
};
//...
try {
A a;
} catch(...) {
// C++03 will catch the exception
}
size()
of containers is now required to run in O(1) 容器的size()
现在需要在O(1)中运行
std::list<double> list;
// ...
size_t s = list.size(); // Might be an O(n) operation in C++03
std::ios_base::failure
does not derive directly from std::exception
anymore std::ios_base::failure
不再直接从std::exception
派生
While the direct base-class is new, std::runtime_error
is not. 虽然直接基类是新的,但std::runtime_error
不是。 Thus: 从而:
try {
std::cin >> variable; // exceptions enabled, and error here
} catch(std::runtime_error &) {
std::cerr << "C++11\n";
} catch(std::ios_base::failure &) {
std::cerr << "Pre-C++11\n";
}
#4楼
One potentially dangerous backward-incompatible change is in constructors of sequence containers such as std::vector
, specifically in the overload specifying initial size. 一个潜在危险的向后不兼容的变化是序列容器的构造函数,例如std::vector
,特别是在指定初始大小的重载中。 Where in C++03, they copied a default-constructed element, in C++11 they default-construct each one. 在C ++ 03中,他们复制了一个默认构造的元素,在C ++ 11中,他们默认构造每个元素。
Consider this example (using boost::shared_ptr
so that it's valid C++03): 考虑这个例子(使用boost::shared_ptr
这样它就是有效的C ++ 03):
#include <deque>
#include <iostream>
#include "boost/shared_ptr.hpp"
struct Widget
{
boost::shared_ptr<int> p;
Widget() : p(new int(42)) {}
};
int main()
{
std::deque<Widget> d(10);
for (size_t i = 0; i < d.size(); ++i)
std::cout << "d[" << i << "] : " << d[i].p.use_count() << '\n';
}
C++11 Live example C ++ 11 Live示例
The reason is that C++03 specified one overload for both "specify size and prototype element" and "specify size only," like this (allocator arguments omitted for brevity): 原因是C ++ 03为“指定大小和原型元素”和“仅指定大小”指定了一个重载,就像这样(为简洁省略了allocator参数):
container(size_type size, const value_type &prototype = value_type());
This will always copy prototype
into the container size
times. 这将始终将prototype
复制到容器size
时间。 When called with just one argument, it will therefore create size
copies of a default-constructed element. 当使用一个参数调用时,它将创建默认构造元素的size
副本。
In C++11, this constructor signature was removed and replaced with these two overloads: 在C ++ 11中,删除了此构造函数签名并替换为这两个重载:
container(size_type size);
container(size_type size, const value_type &prototype);
The second one works as before, creating size
copies of the prototype
element. 第二个像以前一样工作,创建prototype
元素的size
副本。 However, the first one (which now handles calls with only the size argument specified) default-constructs each element individually. 但是,第一个(现在只处理指定了size参数的调用)默认构造每个元素。
My guess for the reason of this change is that the C++03 overload wouldn't be usable with a move-only element type. 我猜测这种变化的原因是C ++ 03重载不适用于只移动元素类型。 But it's a breaking change none the less, and one seldom documented at that. 但它仍然是一个突破性的变化,而且很少有人记录在案。
#5楼
The result of a failed read from an std::istream
has changed. 从std::istream
读取失败的结果已更改。 CppReference summarizes it nicely: CppReference很好地总结了它:
If extraction fails (eg if a letter was entered where a digit is expected),
value
is left unmodified andfailbit
is set. 如果提取失败(例如,如果输入了预期数字的字母),则value
保持failbit
并设置failbit
。 (until C++11) (直到C ++ 11)If extraction fails, zero is written to
value
andfailbit
is set. 如果提取失败,则将零写入value
并设置failbit
。 If extraction results in the value too large or too small to fit invalue
,std::numeric_limits<T>::max()
orstd::numeric_limits<T>::min()
is written andfailbit
flag is set. 如果提取结果的值太大或太小std::numeric_limits<T>::max()
适合value
,则写入std::numeric_limits<T>::max()
或std::numeric_limits<T>::min()
并设置failbit
标志。 (since C++11) (自C ++ 11以来)
This is primarily an issue if you are used to the new semantics and then have to write using C++03. 如果您习惯于新语义然后必须使用C ++ 03编写,那么这主要是一个问题。 The following is not particularly good practice but well-defined in C++11: 以下不是特别好的做法,但在C ++ 11中定义良好:
int x, y;
std::cin >> x >> y;
std::cout << x + y;
However, in C++03, the above code uses an uninitialized variable and thus has undefined behaviour. 但是,在C ++ 03中,上面的代码使用了未初始化的变量,因此具有未定义的行为。
#6楼
This thread What differences, if any, between C++03 and C++0x can be detected at run-time has examples (copied from that thread) to determine language differences, for example by exploiting C++11 reference collapsing: 此线程在运行时可以检测到C ++ 03和C ++ 0x之间的差异(如果有的话)有示例(从该线程复制)以确定语言差异,例如通过利用C ++ 11引用折叠:
template <class T> bool f(T&) {return true; }
template <class T> bool f(...){return false;}
bool isCpp11()
{
int v = 1;
return f<int&>(v);
}
and c++11 allowing local types as template parameters: 和c ++ 11允许本地类型作为模板参数:
template <class T> bool cpp11(T) {return true;} //T cannot be a local type in C++03
bool cpp11(...){return false;}
bool isCpp0x()
{
struct local {} var; //variable with local type
return cpp11(var);
}