C ++ 03 ve C ++ 11 arasında, varsa, çalışma zamanında ne gibi farklılıklar tespit edilebilir?


116

Bir C derleyicisi ile derlendiğinde 0 döndüren ve bir C ++ derleyicisi ile derlendiğinde 1 döndüren bir işlev yazmak mümkündür (önemsiz sulüsyon ile #ifdef __cplusplus ilginç değildir).

Örneğin:

int isCPP()
{
    return sizeof(char) == sizeof 'c';
}

Tabii ki, yukarıdakiler yalnızca sizeof (char) aynısizeof (int)

Başka, daha taşınabilir bir çözüm şuna benzer:

int isCPP()
{
    typedef int T;
    {
       struct T 
       {
           int a[2];
       };
       return sizeof(T) == sizeof(struct T);
    }
}

Örneklerin% 100 doğru olup olmadığından emin değilim, ama fikri anladınız. Aynı işlevi yazmanın başka yolları da olduğuna inanıyorum.

C ++ 03 ve C ++ 11 arasında, varsa, çalışma zamanında ne gibi farklılıklar tespit edilebilir? Başka bir deyişle, uygun bir C ++ 03 derleyicisi veya bir C ++ 11 derleyicisi tarafından derlendiğini gösteren bir boole değeri döndüren benzer bir işlev yazmak mümkün müdür?

bool isCpp11()
{ 
    //???
} 

10
Ve bu egzersizin amacı nedir? Birincisi, bir makronuz var ve ikinci olarak, derleyicilerin C ++ 0x'in tüm özelliklerini uygulamaya başlaması birkaç yıl alacak, bu arada bir karışım olacak. Dolayısıyla, tek makul test, derleyicinin bir sürüm makrosudur.
— Gene Bushuyev

4
Bu gerçek bir sorunun faturasına uymuyor, ancak kurallara uymak çok ilginç görünüyor!
— David Heffernan

4
@Gene ve diğerleri: İlginç olan ancak pragmatik "noktayı" görmediğiniz tüm soruları ekliyor musunuz?
— Armen Tsirunyan

2
"Genel olarak gerçekleri, referansları veya belirli uzmanlığı içeren yanıtlar bekliyoruz". Sanırım bu soru bu beklentileri karşılıyor, yeniden açılmak için oy verin.
— Karel Petranek

6
@sixlettervariables: İfadenin daha iyi olabileceği tartışmasına kesinlikle açık olsa da, bana sorunun temel fikri (eğer varsa, C ++ 03 ve C ++ 0x arasındaki farklar çalıştırmada tespit edilebilir) zaman?) tamamen meşrudur. Kodun her ikisinde de derlenmesi ve çalıştırılması gerektiği göz önüne alındığında, C ++ 0x'deki son değişikliklerle ilgili olarak da ifade edilebilir. Bu bana sorulacak tamamen meşru bir soru gibi görünüyor.
— Jerry Coffin

Yanıtlar:


108

Çekirdek Dil

Bir numaralandırıcıya aşağıdakileri kullanarak erişim :::

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

Yeni anahtar kelimeleri de kötüye kullanabilirsiniz

struct a { };
struct b { a a1, a2; };

struct c : a {
  static b constexpr (a());
};

bool isCpp0x() {
  return (sizeof c::a()) == sizeof(b);
}

Ayrıca, dize değişmezlerinin artık char*

bool isCpp0xImpl(...) { return true; }
bool isCpp0xImpl(char*) { return false; }

bool isCpp0x() { return isCpp0xImpl(""); }

Yine de bunu gerçek bir uygulama üzerinde çalıştırma olasılığınız nedir bilmiyorum. Sömüren biriauto

struct x { x(int z = 0):z(z) { } int z; } y(1);

bool isCpp0x() {
  auto x(y);
  return (y.z == 1);
}

Aşağıdakiler, C ++ 0x'e operator int&&bir dönüştürme işlevi int&&ve intardından mantıksal-ve C ++ 03'te bir dönüştürme olduğu gerçeğine dayanmaktadır.

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

Bu test durumu GCC'de C ++ 0x için çalışmaz (bir hata gibi görünür) ve clang için C ++ 03 modunda çalışmaz. Bir clang PR dosyası açıldı .

Enjekte sınıf isimleri değiştirilmiş tedavisi C ++ 11 şablonları:

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

Değişiklikleri göstermek için birkaç "bunun C ++ 03 veya C ++ 0x olup olmadığını algıla" kullanılabilir. Aşağıda, başlangıçta böyle bir değişikliği göstermek için kullanılan, ancak şimdi C ++ 0x veya C ++ 03'ü test etmek için kullanılan ince ayarlı bir test senaryosu var.

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

Standart Kitaplık

operator void*C ++ 0x'in eksikliğini tespit etmestd::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);
}

1
Güzel. Bu çözümün burada -std = c ++ 0x ile ve olmadan g ++ (GCC) 4.6.0 ile çalıştığını doğrulayabilirim.
— Alexander

2
Bu trueMSVC 2005 ve sonrası için geri dönüyor ve MSVC 2003'te bir derleme hatası.
— Anthony Williams

1
Ah canım, geriye dönük uyumluluğu bozdular!
— avakar

14
@Johannes: Haftalardır yaşadığın en eğlenceli şey bu değil mi? ; -]
— ildjarn

4
Bunların hepsini çok ilginç buluyorum, ancak bence en akıllıca (...)karşı (char*)aramalar. Bunu gerçekten beğendim!
— corsiKa

44

Ben bir ilham aldık kırma değişiklikler ++ 11 C tanıtıldı sen? :

#define u8 "abc"

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

Bu, makro genişletmeye göre öncelikli olan yeni dize değişmezlerine dayanır.


1
+1: Gerçekten çok ilginç, ancak teknik olarak ön işlemciyi kullanmama gerekliliğini ortadan kaldırıyor. Ancak kısıtlama bu kadar güzel cevapları göz ardı etmeyi amaçlamıyordu :)
— Armen Tsirunyan

1
İşlevi bir ile takip ederseniz #undef u8, önişlemci kullanımı yalnızca programınızda u8(boooo) adında önceden tanımlanmış bir makro varsa gözlemlenebilir . Bu gerçek bir endişe ise, uygulamaya özgü push / pop makro pragmaları / çağrıları kullanılarak hala üzerinde çalışılabilir (çoğu uygulamada bunlara sahip olduğuna inanıyorum).
— James McNellis

3
Oldukça makul bir argüman, C ++ 03 sisteminde birinin simüle edilmiş C ++ 0x yetenekleri sağlamak için u8'i tanımlayabileceğidir. Yine de cevabı gerçekten beğendim.
— Christopher Smith

1
Bu isCpp0x işlevini ayrı bir çeviri birimine taşıyabilirsiniz, böylece bu makro şeyi diğer kodu etkilemez.
— unkulunkulu

1
Derleyicinin bazı makro değerleri ayarlamasına güvenmek için ön işlemciyi kullanmakla gerçek dil özelliklerini algılamak için ön işlemciyi kullanmak arasında bir fark olduğunu düşünüyorum. Bu yüzden bu cevabın hile olduğunu düşünmüyorum.
— Orbit'te Hafiflik Yarışları

33

>>Şablonları kapatmak için yeni kuralları kullanarak bir kontrole ne dersiniz :

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

Alternatif olarak aşağıdakiler için hızlı bir kontrol 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));
}

6
+1 Gerçekten harika bir fikir :) Bununla birlikte, pratikte bu, C ++ 0x'i desteklemeyen ancak >> şablonlarda C ++ 0x şeklinde kullanılmasına izin veren Visual C ++ 2005/2088 ile bozulacaktır.
— Karel Petranek

4
Oooh; ADL suistimalini seviyorum! Bununla birlikte, uyumlu bir C ++ 03 uygulamasının adında bir işlevi olamaz std::movemı?
— James McNellis

1
@FredOverflow: Rahatsız etmem. UI berbat!
— Orbit'te Hafiflik Yarışları

16

Önceki C ++ 'dan farklı olarak, C ++ 0x, bu temel başvuru türü örneğin bir şablon parametresi aracılığıyla tanıtılmışsa başvuru türlerinden başvuru türlerinin oluşturulmasına izin verir:

template <class T> bool func(T&) {return true; } 
template <class T> bool func(...){return false;} 

bool isCpp0x() 
{
    int v = 1;
    return func<int&>(v); 
}

Mükemmel yönlendirme, maalesef geriye dönük uyumluluğu bozmanın bedeli ile gelir.

Başka bir test, şablon bağımsız değişkenleri olarak artık izin verilen yerel türleri temel alabilir:

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

Belki de bunu bir özellik sınıfına dönüştürmeliydim;)
— uwedolinsky

1
+1 Güzel fikir, sadece isC++0xgeçerli bir C ++ tanımlayıcı olup olmadığından emin değilim ;)
— Karel Petranek

1
Referans çıkarımından referans için iyi bir referans nedir?
— Kerrek SB

@ kerrek-sb: Taslak 8.3.2.6'da bundan bahsediyor (Referanslar)
— uwedolinsky

15

Bu tam olarak doğru bir örnek değil, ancak C ile C ++ 0x'i ayırt edebilen ilginç bir örnek (yine de geçersiz C ++ 03):

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

10
Teknik olarak, bu sizeof(int) != 1doğru olmaya dayanır . Olağanüstü büyük chars değerlerine sahip bir 0x sisteminde sonuçlar aynı olabilir. Yine de güzel bir numara.
— Dennis Zickefoose

@Dennis - charher zaman bir bayttır
— Düğüm

4
@Node: bir bayt her zaman 8 bit değildir.
— Alexandre C.

2
@Node sizeof(char)tanım gereği her zaman 1 olacaktır. Ancak CHAR_BIT(limits.h tanımlanan) daha Sonuç olarak 8'den izin yer alan her iki charve int32 bit, bu durumda olabilir sizeof(int) == 1(ve CHAR_BIT == 32).
— Sjoerd

12

Gönderen bu soruya :

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

std::vector<T> test(1);
bool is_cpp0x = !test[0].flag;

Bunun nasıl çalıştığını merak ettim; denedikten sonra, şimdi anlaşıldı: küçük bir hata var. son satırı şu şekilde değiştirirseniz çalışır:bool is_cpp0x = !test[0].flag;
— awx

1
makul: C ++ 0x varsayılan yapıları T, C ++ 03 kopyası yapılarıT()
— awx

9

O kadar kısa olmasa da ... Mevcut C ++ 'da, sınıf şablonu adı o sınıf şablonunun kapsamındaki bir tür adı (şablon adı değil) olarak yorumlanır. Öte yandan, sınıf şablon adı C ++ 0x (N3290 14.6.1 / 1) 'de şablon adı olarak kullanılabilir.

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

9
#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;
}

NB teknik olarak bu, derleyiciyi değil standart kitaplığı test eder ve geçerli C ++ 03 ve geçerli C ++ 0x olmasına rağmen, geçerli C ++ 98 değildir, bu nedenle bazı ince ayarlarla bir C ++ 98 / C ++ 03 / C ++ 0x stdlib
— Jonathan Wakely
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.