Какие различия, если таковые имеются, между 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()
{
//???
}
8 ответов:
Основной Язык
доступ к перечислителю с помощью
::
: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++03struct 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. лязг PR был подан.
The измененная обработка введенных имен классов шаблонов в 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" можно использовать для демонстрации взлома изменения. Ниже приведен измененный testcase, который первоначально использовался для демонстрации такого изменения, но теперь используется для тестирования на 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); }
Я получил вдохновение от какие критические изменения вводятся в 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; }