C ++ 03과 C ++ 11의 런타임에 어떤 차이가 감지 될 수 있습니까?
C 컴파일러로 컴파일하면 0을 반환하고 C ++ 컴파일러로 컴파일하면 1을 반환하는 함수를 작성할 수 있습니다 (사소한 sulution #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()
{
//???
}
핵심 언어
사용하는 열거 액세스 ::
:
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();
}
A couple of "detect whether this is C++03 or C++0x" can be used to demonstrate breaking changes. The following is a tweaked testcase, which initially was used to demonstrate such a change, but now is used to test for C++0x or 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); }
Standard Library
Detecting the lack of operator void*
in 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);
}
I got an inspiration from What breaking changes are introduced in C++11?:
#define u8 "abc"
bool isCpp0x() {
const std::string s = u8"def"; // Previously "abcdef", now "def"
return s == "def";
}
This is based on the new string literals that take precedence over macro expansion.
How about a check using the new rules for >>
closing templates:
#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;
}
Alternatively a quick check for 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));
}
Unlike prior C++, C++0x allows reference types to be created from reference types if that base reference type is introduced through, for example, a template parameter:
template <class T> bool func(T&) {return true; }
template <class T> bool func(...){return false;}
bool isCpp0x()
{
int v = 1;
return func<int&>(v);
}
Perfect forwarding comes at the price of breaking backwards compatibility, unfortunately.
Another test could be based on now-allowed local types as template arguments:
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);
}
This isn't quite a correct example, but it's an interesting example that can distinguish C vs. C++0x (it's invalid C++03 though):
int IsCxx03()
{
auto x = (int *)0;
return ((int)(x+1) != 1);
}
From this question:
struct T
{
bool flag;
T() : flag(false) {}
T(const T&) : flag(true) {}
};
std::vector<T> test(1);
bool is_cpp0x = !test[0].flag;
Though not so concise... In current C++, class template name itself is interpreted as a type name (not a template name) in that class template's scope. On the other hand, class template name can be used as a template name in 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;
}
#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;
}
'development' 카테고리의 다른 글
C # 6의 긴 문자열 보간 라인 (0) | 2020.07.20 |
---|---|
Retrofit-Android로 요청 및 응답 본문을 기록하는 방법은 무엇입니까? (0) | 2020.07.20 |
C #에서 제네릭과 공분산의 공분산 이해 문제 (0) | 2020.07.20 |
소스 코드를 자동으로 들여 쓰는 방법? (0) | 2020.07.20 |
React 컴포넌트에서 컴포넌트 기본 소품을 설정하는 방법 (0) | 2020.07.20 |