c++代码是否可能同时符合c++ 03标准和c++ 11标准,但根据编译的标准做不同的事情?
当前回答
一个潜在的危险的向后不兼容更改是在序列容器的构造函数中,例如std::vector,特别是在指定初始大小的重载中。在c++ 03中,他们复制了一个默认构造的元素,而在c++ 11中,他们默认构造每个元素。
考虑这个例子(使用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++ 03实例
c++ 11实例
原因是c++ 03为“指定大小和原型元素”和“仅指定大小”指定了一个重载,就像这样(为简洁起见,省略了分配器参数):
container(size_type size, const value_type &prototype = value_type());
这将始终复制原型到容器大小的次数。当只使用一个参数调用时,它将创建默认构造元素的大小副本。
在c++ 11中,这个构造函数签名被删除并替换为以下两个重载:
container(size_type size);
container(size_type size, const value_type &prototype);
第二个方法和前面一样,创建原型元素的大小副本。但是,第一个(现在只处理指定size参数的调用)默认单独构造每个元素。
我猜测这一更改的原因是c++ 03重载不能用于仅移动的元素类型。但这毕竟是一个突破性的变化,而且很少有文献记载。
其他回答
在运行时可以检测到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);
}
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);
}
我向您推荐这篇文章和后续文章,其中有一个很好的例子,说明>>如何在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
}
关键部分是main中的行,这是一个表达式。
c++ 03:
1 >> ::three = 0
=> fon< fun< 0 >::two >::one;
fun< 0 >::two = int
=> fon< int >::one
fon< int >::one = true
=> true
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
恭喜你,同一个表达式有两个不同的结果。当然,在我测试时,c++ 03确实出现了一个警告表单Clang。
下面是另一个例子:
#include <iostream>
template<class T>
struct has {
typedef char yes;
typedef yes (&no)[2];
template<int> struct foo;
template<class U> static yes test(foo<U::bar>*);
template<class U> static no test(...);
static bool const value = sizeof(test<T>(0)) == sizeof(yes);
};
enum foo { bar };
int main()
{
std::cout << (has<foo>::value ? "yes" : "no") << std::endl;
}
打印:
Using c++03: no
Using c++11: yes
看看Coliru的结果
一个潜在的危险的向后不兼容更改是在序列容器的构造函数中,例如std::vector,特别是在指定初始大小的重载中。在c++ 03中,他们复制了一个默认构造的元素,而在c++ 11中,他们默认构造每个元素。
考虑这个例子(使用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++ 03实例
c++ 11实例
原因是c++ 03为“指定大小和原型元素”和“仅指定大小”指定了一个重载,就像这样(为简洁起见,省略了分配器参数):
container(size_type size, const value_type &prototype = value_type());
这将始终复制原型到容器大小的次数。当只使用一个参数调用时,它将创建默认构造元素的大小副本。
在c++ 11中,这个构造函数签名被删除并替换为以下两个重载:
container(size_type size);
container(size_type size, const value_type &prototype);
第二个方法和前面一样,创建原型元素的大小副本。但是,第一个(现在只处理指定size参数的调用)默认单独构造每个元素。
我猜测这一更改的原因是c++ 03重载不能用于仅移动的元素类型。但这毕竟是一个突破性的变化,而且很少有文献记载。
从std::istream读取失败的结果已经改变。CppReference总结得很好:
如果提取失败(例如,如果在需要数字的地方输入了字母),则value保持不变,并设置failbit。(直到c++ 11) 如果提取失败,则将0写入值并设置failbit。如果提取结果值太大或太小,不适合值,std::numeric_limits<T>::max()或std::numeric_limits<T>::min()被写入,并设置failbit标志。(因为c++ 11)
如果您已经习惯了新的语义,然后不得不使用c++ 03编写,那么这将是一个主要问题。以下不是特别好的实践,但在c++ 11中定义良好:
int x, y;
std::cin >> x >> y;
std::cout << x + y;
然而,在c++ 03中,上述代码使用了一个未初始化的变量,因此具有未定义的行为。
推荐文章
- Std::auto_ptr改为Std::unique_ptr
- int的最大值
- c++中有最大数组长度限制吗?
- 什么是“参数依赖查找”(又名ADL,或“Koenig查找”)?
- 公共朋友交换成员函数
- 如何在Go中使用c++
- 自定义c++分配器的引人注目的例子?
- RAII和c++中的智能指针
- 如何构建和使用谷歌TensorFlow c++ api
- 断言是邪恶的吗?
- 下面这些短语在c++中是什么意思:0 -,default-和value-initialization?
- 在STL地图中,使用map::insert比[]更好吗?
- C++ Linux的想法?
- 有效,但毫无价值的语法在开关情况下?
- 如何为Fedora安装g++ ?