Какие различия, если таковые имеются, между С++ 03 и С++ 11 могут быть обнаружены во время выполнения?
Можно написать функцию, которая при компиляции с компилятором C вернет 0 и при компиляции с компилятором С++ вернет 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% правильны, но вы получаете идею. Я считаю, что есть и другие способы написать одну и ту же функцию.
Какие различия, если таковые имеются, между С++ 03 и С++ 11 могут быть обнаружены во время выполнения? Другими словами, можно ли написать аналогичную функцию, которая вернет логическое значение, указывающее, скомпилировано ли оно компилятором С++ 03 или компилятором С++ 11?
bool isCpp11()
{
//???
}
Ответы
Ответ 1
Основной язык
Доступ к счетчику с помощью ::
:
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&&
в С++ 0x и преобразованием в int
, за которым следуют логические и в С++ 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);
}
Этот тестовый сценарий не работает для С++ 0x в GCC (выглядит как ошибка) и не работает в режиме С++ 03 для clang. Опубликован клик PR.
измененная обработка введенных имен классов шаблонов в С++ 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();
}
Пара демонстрирует, что это С++ 03 или С++ 0x, для демонстрации изменений. Ниже приведен теневой тестовый файл, который изначально использовался для демонстрации такого изменения, но теперь он используется для тестирования С++ 0x или С++ 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*
в С++ 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);
}
Ответ 2
Я получил вдохновение от Какие изменения вступили в С++ 11?:
#define u8 "abc"
bool isCpp0x() {
const std::string s = u8"def"; // Previously "abcdef", now "def"
return s == "def";
}
Это основано на новых строковых литералах, которые имеют приоритет над расширением макроса.
Ответ 3
Как насчет проверки с использованием новых правил для >>
закрывающих шаблонов:
#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));
}
Ответ 4
В отличие от предыдущего С++, С++ 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);
}
Ответ 5
Это не совсем правильный пример, но это интересный пример, который может различать C vs. С++ 0x (хотя это недействительный С++ 03):
int IsCxx03()
{
auto x = (int *)0;
return ((int)(x+1) != 1);
}
Ответ 6
Из этот вопрос:
struct T
{
bool flag;
T() : flag(false) {}
T(const T&) : flag(true) {}
};
std::vector<T> test(1);
bool is_cpp0x = !test[0].flag;
Ответ 7
Хотя не так кратким...
В текущем С++ имя шаблона класса интерпретируется как имя типа
(а не имя шаблона) в этой области шаблонов классов.
С другой стороны, имя шаблона класса может использоваться как имя шаблона в
С++ 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;
}
Ответ 8
#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;
}