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.