在运行时可以检测到 C + + 03和 C + + 11之间的哪些差异(如果有的话) ?

编写一个函数是可能的,当用 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()
{
//???
}
8773 次浏览

核心语言

使用 ::访问枚举数:

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);
}

You can also abuse the new keywords

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);
}

下面是基于这样一个事实: 在 C + + 0x 中,operator int&&是到 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) ,在 C + + 03模式中对 clang 也不起作用。已经提交了一份“当当公关”申请.

The 注入类名的修改处理 of templates in 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 和 C + + 0x (尽管它是无效的 C + + 03) :

 int IsCxx03()
{
auto x = (int *)0;
return ((int)(x+1) != 1);
}

使用 >>关闭模板的新规则检查一下怎么样:

#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 + + 11中引入了哪些突破性的改变得到了一个灵感:

#define u8 "abc"


bool isCpp0x() {
const std::string s = u8"def"; // Previously "abcdef", now "def"
return s == "def";
}

这是基于优先于宏展开的新字符串文字。

与之前的 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);
}

Perfect forwarding comes at the price of breaking backwards compatibility, unfortunately.

另一个测试可以基于现在允许的作为模板参数的本地类型:

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 + + 中,类模板名本身被解释为类型名 (不是模板名称)在该类模板的范围内。 On the other hand, class template name can be used as a template name in C + + 0x (N329014.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;
}

来自 这个问题:

struct T
{
bool flag;
T() : flag(false) {}
T(const T&) : flag(true) {}
};


std::vector<T> test(1);
bool is_cpp0x = !test[0].flag;
#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;
}