在运行时可以检测到C++03和C++11之间的差异(如果有的话)
What differences, if any, between C++03 and C++11 can be detected at run-time?
可以编写一个函数,当用C编译器编译时,它将返回0,当用C++编译器编译时将返回1(#ifdef __cplusplus
不感兴趣)。
例如:
int isCPP()
{
return sizeof(char) == sizeof 'c';
}
当然,只有当sizeof (char)
与sizeof (int)
不同时,上述方法才有效
另一个更便携的解决方案是这样的:
int isCPP()
{
typedef int T;
{
struct T
{
int a[2];
};
return sizeof(T) == sizeof(struct T);
}
}
我不确定这些例子是否100%正确,但你已经明白了。我相信还有其他方法可以编写相同的函数。
在运行时可以检测到C++03和C++11之间的哪些差异(如果有的话)?换句话说,是否可以编写一个类似的函数,返回一个布尔值,指示它是由兼容的C++03编译器还是C++11编译器编译的?
bool isCpp11()
{
//???
}
核心语言
使用::
:访问枚举器
template<int> struct int_ { };
template<typename T> bool isCpp0xImpl(int_<T::X>*) { return true; }
template<typename T> bool isCpp0xImpl(...) { return false; }
enum A { X };
bool isCpp0x() {
return isCpp0xImpl<A>(0);
}
你也可以滥用新的关键字
struct a { };
struct b { a a1, a2; };
struct c : a {
static b constexpr (a());
};
bool isCpp0x() {
return (sizeof c::a()) == sizeof(b);
}
此外,字符串文字不再转换为char*
bool isCpp0xImpl(...) { return true; }
bool isCpp0xImpl(char*) { return false; }
bool isCpp0x() { return isCpp0xImpl(""); }
不过,我不知道你有多大可能让它在真正的实现中发挥作用。利用auto
的
struct x { x(int z = 0):z(z) { } int z; } y(1);
bool isCpp0x() {
auto x(y);
return (y.z == 1);
}
以下是基于以下事实:operator int&&
是C++0x中int&&
的转换函数,以及C++03 中逻辑和之后的int
的转换
struct Y { bool x1, x2; };
struct A {
operator int();
template<typename T> operator T();
bool operator+();
} a;
Y operator+(bool, A);
bool isCpp0x() {
return sizeof(&A::operator int&& +a) == sizeof(Y);
}
该测试用例不适用于GCC中的C++0x(看起来像一个bug),也不适用于clang的C++03模式。已经提交了一份叮当作响的PR。
C++11:中模板注入类名的改进处理
template<typename T>
bool g(long) { return false; }
template<template<typename> class>
bool g(int) { return true; }
template<typename T>
struct A {
static bool doIt() {
return g<A>(0);
}
};
bool isCpp0x() {
return A<void>::doIt();
}
可以使用几个"检测这是C++03还是C++0x"来演示中断更改。下面是一个经过调整的测试用例,最初用于演示这样的更改,但现在用于测试C++0x或C++03。
struct X { };
struct Y { X x1, x2; };
struct A { static X B(int); };
typedef A B;
struct C : A {
using ::B::B; // (inheriting constructor in c++0x)
static Y B(...);
};
bool isCpp0x() { return (sizeof C::B(0)) == sizeof(Y); }
标准库
C++0x'std::basic_ios
中operator void*
缺失的检测
struct E { E(std::ostream &) { } };
template<typename T>
bool isCpp0xImpl(E, T) { return true; }
bool isCpp0xImpl(void*, int) { return false; }
bool isCpp0x() {
return isCpp0xImpl(std::cout, 0);
}
我从C++11中引入了哪些突破性的变化中获得了灵感:
#define u8 "abc"
bool isCpp0x() {
const std::string s = u8"def"; // Previously "abcdef", now "def"
return s == "def";
}
这是基于优先于宏扩展的新字符串文字。
如何使用>>
关闭模板的新规则进行检查:
#include <iostream>
const unsigned reallyIsCpp0x=1;
const unsigned isNotCpp0x=0;
template<unsigned>
struct isCpp0xImpl2
{
typedef unsigned isNotCpp0x;
};
template<typename>
struct isCpp0xImpl
{
static unsigned const reallyIsCpp0x=0x8000;
static unsigned const isNotCpp0x=0;
};
bool isCpp0x() {
unsigned const dummy=0x8000;
return isCpp0xImpl<isCpp0xImpl2<dummy>>::reallyIsCpp0x > ::isNotCpp0x>::isNotCpp0x;
}
int main()
{
std::cout<<isCpp0x()<<std::endl;
}
或者,快速检查std::move
:
struct any
{
template<typename T>
any(T const&)
{}
};
int move(any)
{
return 42;
}
bool is_int(int const&)
{
return true;
}
bool is_int(any)
{
return false;
}
bool isCpp0x() {
std::vector<int> v;
return !is_int(move(v));
}
与以前的C++不同,如果基本引用类型是通过模板参数引入的,则C++0x允许从引用类型创建引用类型:
template <class T> bool func(T&) {return true; }
template <class T> bool func(...){return false;}
bool isCpp0x()
{
int v = 1;
return func<int&>(v);
}
不幸的是,完美的转发是以破坏向后兼容性为代价的。
另一个测试可以基于现在允许的本地类型作为模板参数:
template <class T> bool cpp0X(T) {return true;} //cannot be called with local types in C++03
bool cpp0X(...){return false;}
bool isCpp0x()
{
struct local {} var;
return cpp0X(var);
}
这不是一个非常正确的例子,但它是一个有趣的例子,可以区分C与C++0x(尽管它是无效的C++03):
int IsCxx03()
{
auto x = (int *)0;
return ((int)(x+1) != 1);
}
来自这个问题:
struct T
{
bool flag;
T() : flag(false) {}
T(const T&) : flag(true) {}
};
std::vector<T> test(1);
bool is_cpp0x = !test[0].flag;
虽然不那么简洁。。。在当前的C++中,类模板名称本身被解释为类型名称(不是模板名称)。另一方面,类模板名称可以用作C++0x(N3290 14.6.1/1)。
template< template< class > class > char f( int );
template< class > char (&f(...))[2];
template< class > class A {
char i[ sizeof f< A >(0) ];
};
bool isCpp0x() {
return sizeof( A<int> ) == 1;
}
#include <utility>
template<typename T> void test(T t) { t.first = false; }
bool isCpp0x()
{
bool b = true;
test( std::make_pair<bool&>(b, 0) );
return b;
}
- 将向量之间的数字放在另一个向量之间<vector>>如果两个数字的差值为 1
- 如何在 assert() 和 static_assert() 之间调度,如果在 constexpr 上下文中依赖?
- 如果我的容器位于两个现有值之间,那么伪造迭代器类别是否合理
- #define DATA 10 和 # (如果定义了 DATA)之间的差异
- 如果我在下面的代码中使用 list 而不是 vector,为什么在我尝试在迭代器之间执行减法的行中编译失败?
- 如果检查和内联条件之间是否存在编译器差异
- 如果两个线程调用同一个函数,但函数中的所有变量都是局部变量,我还需要担心线程之间共享数据吗?
- 如果值来自成员变量,则复制初始化和参考初始化之间的C 差异
- 如果 strlen 在 char 数组之间遇到空格,它会怎么做
- 重命名两个目录中的文件名,如果它们之间的某些字符匹配 - 矢量下标超出范围
- 如果 2 个数字之间的差值在 1 到 100 之间,则应运行 if 语句
- 如果用像素来给出两条线(外部和内部)之间的边缘(外部和内部)之间的边缘,则如何计算(x,y)坐标
- 对于数据成员,如果包含对象已在动态内存中,则动态分配此变量(或不动态分配)之间是否有任何区别
- 如果和同时中断之间的区别
- 如果"foo"是引用变量,[&foo]{ ... } 捕获和 [foo]{ ... } 捕获之间有区别吗?
- C++数组运算符和 *(数组 + 索引)之间有什么区别(如果有)
- ShellExecute和CMD命令之间有什么区别,如果有的话
- {x} 和 '= {x}' 初始化之间有什么区别(如果有的话)?
- c ++:TCP服务器"bind"功能失败(errno 98),如果我在两次连续应用程序启动之间没有等待足够的时间
- c ++ 如何提取单词之间的空格(如果有)