런타임에 C ++ 03과 C ++ 11간에 어떤 차이점이 발견 될 수 있습니까?


116

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()
{ 
    //???
} 

10
그리고이 운동의 요점은 무엇입니까? 첫째, 매크로가 있고 둘째로 컴파일러가 C ++ 0x의 모든 기능을 구현하기 시작하는 데 몇 년이 걸리며 그 동안에는 혼합이 될 것입니다. 따라서 유일한 합리적인 테스트는 컴파일러 인 버전 매크로입니다.
Gene Bushuyev 2011 년

4
이것은 실제 질문은 아니지만 규칙을 따르기에는 너무 흥미로워 보입니다!
David Heffernan 2011-06-25

4
@Gene et al : 흥미롭지 만 실용적인 "요점"이 보이지 않는 모든 질문에 반대표를 던지십니까?
Armen Tsirunyan 2011 년

2
"우리는 일반적으로 사실, 참조 또는 특정 전문 지식과 관련된 답변을 기대합니다." 이 질문이 이러한 기대에 부합한다고 생각합니다.
Karel Petranek 2011-06-26

6
@sixlettervariables : 문구가 더 나을 수 있다는 주장은 확실히 열려 있지만 질문의 근본적인 개념 (있는 경우 C ++ 03과 C ++ 0x 사이의 차이점이 실행시 감지 될 수 있음)은 시간?)은 완벽하게 합법적입니다. 코드가 둘 다에서 컴파일되고 실행되어야한다는 점을 감안할 때 C ++ 0x의 주요 변경 사항에 대한 것으로 표현 될 수도 있습니다. 그것은 나에게도 물어볼 수있는 완벽하게 합법적 인 질문처럼 보인다.
Jerry Coffin

답변:


108

핵심 언어

다음을 사용하여 열거 자에 액세스 :::

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

다음은 C ++ 0x에서 operator int&&변환 함수 라는 사실 int&&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);
}

이 테스트 케이스는 GCC의 C ++ 0x (버그처럼 보임)에서는 작동하지 않으며 clang의 C ++ 03 모드에서는 작동하지 않습니다. clang PR이 제출되었습니다 .

주입 클래스 이름의 수정 처리 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);
}

1
좋은. 이 솔루션이 -std = c ++ 0x를 사용하거나 사용하지 않고 g ++ (GCC) 4.6.0에서 작동 함을 확인할 수 있습니다.
Alexander

2
이것은 trueMSVC 2005 이후에 반환 되고 MSVC 2003에서 컴파일 오류가 발생합니다.
Anthony Williams

1
오, 그들은 이전 버전과의 호환성을 깨뜨 렸습니다!
avakar

14
@Johannes :이게 몇 주 만에 가장 재밌었 지? ;-]
ildjarn

4
나는 이것들이 매우 흥미 롭다고 생각하지만 가장 영리한 것은 (...)vs (char*)콜 이라고 생각 합니다. 정말 좋아요!
corsiKa

44

C ++ 11에 도입 된 주요 변경 사항 에서 영감을 얻었습니다 . :

#define u8 "abc"

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

이는 매크로 확장보다 우선하는 새 문자열 리터럴을 기반으로합니다.


1
+1 : 실제로 매우 흥미롭지 만 기술적으로 전처리기를 사용하지 않는 요구 사항을 위반합니다. 그러나 제한은 그런 좋은 대답을 기각하기위한 것이 아닙니다. :)
Armen Tsirunyan 2011-06-24

1
글쎄요, 당신이 함수를 a #undef u8로 따라 가면 프로그램에 u8(boooo) 라는 이름의 이전에 정의 된 매크로가있는 경우에만 전 처리기 사용을 관찰 할 수 있습니다 . 이것이 진짜 관심사라면 구현 별 푸시 / 팝 매크로 pragma / calls를 사용하여 해결할 수 있습니다 (대부분의 구현에는 이러한 기능이 있다고 생각합니다).
James McNellis 2011-06-24

3
상당히 합리적인 주장 중 하나는 C ++ 03 시스템에서 누군가가 시뮬레이션 된 C ++ 0x 기능을 제공하기 위해 u8을 #define 할 수 있다는 것입니다. 그래도 대답이 정말 마음에 들어요.
Christopher Smith

1
이 isCpp0x 함수를 별도의 변환 단위로 이동하면이 매크로가 다른 코드에 영향을주지 않습니다.
unkulunkulu jul.

1
일부 매크로 값을 설정하는 컴파일러에 의존하기 위해 전처리기를 사용하는 것과 실제 언어 기능을 감지하기 위해 전처리기를 사용하는 것에는 차이가 있다고 생각합니다. 그래서이 답변이 속임수라고 생각하지 않습니다.
궤도

33

>>템플릿 마감에 대한 새 규칙을 사용하여 확인하는 방법은 무엇입니까?

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

6
+1 정말 멋진 아이디어 :) 그러나 실제로 이것은 C ++ 0x를 지원하지 않지만 >>를 C ++ 0x 방식으로 템플릿에서 사용할 수있는 Visual C ++ 2005/2088에서는 깨질 것입니다.
Karel Petranek 2011 년

4
우, 나는 ADL 남용을 좋아합니다! 그러나 준수 C ++ 03 구현에는 std::move? 라는 함수가있을 수 없습니다 .
James McNellis 2011-06-24

1
@FredOverflow : 귀찮게하지 않습니다. UI가 형편 없다!
궤도

16

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

아마도 나는 그것을 특성 클래스로 바꾸 었어 야했다;)
uwedolinsky 2011-06-24

1
+1 좋은 아이디어 isC++0x입니다. 유효한 C ++ 식별자 인지 확실하지 않습니다 .)
Karel Petranek 2011-06-24

1
참조 추론에서 참조에 대한 좋은 참조는 무엇입니까?
Kerrek SB 2011

@ kerrek-sb : 초안은 8.3.2.6에서 이에 대해 이야기합니다. (참조)
uwedolinsky 2011 년

15

이것은 정확한 예는 아니지만 C와 C ++ 0x를 구분할 수있는 흥미로운 예입니다 (하지만 유효하지 않은 C ++ 03).

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

10
기술적으로 이것은 sizeof(int) != 1사실에 달려 있습니다. chars 가 매우 큰 0x 시스템 에서는 결과가 동일 할 수 있습니다. 그래도 여전히 깔끔한 속임수입니다.
Dennis Zickefoose 2011 년

@Dennis- char그래도 항상 1 바이트
Node

4
@Node : 1 바이트가 항상 8 비트는 아닙니다.
Alexandre C.

2
@Node sizeof(char)는 정의에 따라 항상 1입니다. 그러나 CHAR_BIT(limits.h 정의) 이상의 결과, 제보다시킨다 모두 charint32 비트,이 경우에있을 수있는 sizeof(int) == 1(그리고 CHAR_BIT == 32).
Sjoerd

12

에서 이 질문 :

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

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

나는 이것이 어떻게 작동 할 수 있는지 궁금했다. 시도해 보면 이제 분명합니다. 약간의 버그가 있습니다. 마지막 줄을 다음과 같이 변경하면 작동합니다.bool is_cpp0x = !test[0].flag;
awx

1
그럴듯한 : C ++ 0x 기본 구문 인 T반면 C ++ 03은 다음에서 구문을 복사합니다T()
awx

9

간결하지는 않지만 ... 현재 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;
}

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는 기술적으로 컴파일러가 아닌 표준 라이브러리를 테스트하며 유효한 C ++ 03 및 유효한 C ++ 0x이지만 유효한 C ++ 98이 아니므로 C ++ 98 /을 감지하기 위해 약간의 조정을 할 수 있습니다. C ++ 03 / C ++ 0x stdlib
Jonathan Wakely 2011 년
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.