Какие различия, если таковые имеются, между C ++ 03 и C ++ 11 могут быть обнаружены во время выполнения? - PullRequest
116 голосов
/ 25 июня 2011

Можно написать функцию, которая при компиляции с помощью компилятора 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()
{ 
    //???
} 

Ответы [ 8 ]

107 голосов
/ 25 июня 2011

Базовый язык

Доступ к счетчику с использованием :::

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&& является функцией преобразования в int&& в C ++ 0x, а преобразование в int сопровождается логическим и в C ++ 03

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

Этот тест-кейс не работает для C ++ 0x в GCC (выглядит как ошибка) и не работает в режиме C ++ 03 для clang. Звонил пиарщик .

Модифицированная обработка введенных имен классов шаблонов в 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); }

Стандартная библиотека

Обнаружение отсутствия operator void* в C ++ 0x 'std::basic_ios

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);
}
43 голосов
/ 25 июня 2011

Я получил вдохновение от Какие принципиальные изменения внесены в C ++ 11? :

#define u8 "abc"

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

Это основано на новых строковых литералах, которые имеют приоритет над раскрытием макроса.

33 голосов
/ 25 июня 2011

Как насчет проверки с использованием новых правил для >> шаблонов закрытия:

#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));
}
16 голосов
/ 25 июня 2011

В отличие от предыдущего 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);
}
15 голосов
/ 25 июня 2011

Это не совсем правильный пример, но это интересный пример, который может отличить C от C ++ 0x (хотя это недопустимый C ++ 03):

 int IsCxx03()
 {
   auto x = (int *)0;
   return ((int)(x+1) != 1);
}
12 голосов
/ 25 июня 2011

С этот вопрос :

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

std::vector<T> test(1);
bool is_cpp0x = !test[0].flag;
9 голосов
/ 25 июня 2011
#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;
}
9 голосов
/ 25 июня 2011

Хотя это и не так кратко ... В текущем 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;
}
...