C ++ 11과의 호환성 향상


12

여러 플랫폼에서 실행해야하는 대규모 소프트웨어 응용 프로그램에서 작업하고 있습니다. 이러한 플랫폼 중 일부는 C ++ 11의 일부 기능 (예 : MSVS 2010)을 지원하고 일부는 지원하지 않습니다 (예 : GCC 4.3.x). 나는이 상황이 몇 년 동안 계속 될 것으로 기대합니다 (내 추측으로는 3-5 년).

그 점을 감안할 때, 가능한 최소한의 유지 관리를 통해 구형 컴파일러로 컴파일 할 C ++ 11 코드를 작성할 수있는 호환성 인터페이스를 설정하고 싶습니다. 전반적으로, 목표는 #ifdef를 합리적으로 최소화하면서이를 지원하는 플랫폼에서 기본적인 C ++ 11 구문 / 기능을 활성화하고 그렇지 않은 플랫폼에서 에뮬레이션을 제공하는 것입니다.

std :: move ()로 시작해 봅시다. 호환성을 달성하는 가장 확실한 방법은 다음과 같은 것을 일반적인 헤더 파일에 넣는 것입니다.

#if !defined(HAS_STD_MOVE)
namespace std { // C++11 emulation
  template <typename T> inline T& move(T& v) { return v; }
  template <typename T> inline const T& move(const T& v) { return v; }
}
#endif // !defined(HAS_STD_MOVE)

이를 통해 사람들은 다음과 같은 것을 쓸 수 있습니다.

std::vector<Thing> x = std::move(y);

... 불의와 함께. C ++ 11에서 원하는 것을 수행하고 C ++ 03에서 가능한 최선을 다합니다. 마지막으로 C ++ 03 컴파일러의 마지막을 제거하면이 코드는 그대로 유지 될 수 있습니다.

그러나 표준에 따르면 std네임 스페이스에 새 심볼을 삽입하는 것은 불법 입니다. 이것이 이론입니다. 내 질문은 : 실제로 말하기 는 순방향 호환성을 달성하는 방법 으로이 작업을 수행하는 데 해가 있습니까?


1
Boost는 이미 이것의 상당 부분을 제공하고 있으며 가능한 경우 / 사용 가능한 경우 새로운 기능을 사용하는 코드를 이미 가지고 있으므로 Boost가 제공하는 기능 만 사용하여 완료 할 수 있습니다. 물론 한계가 있습니다. 대부분의 새로운 기능은 라이브러리 기반 솔루션이 적합하지 않기 때문에 특별히 추가되었습니다.
Jerry Coffin

예, 구문 적 변경이 아닌 라이브러리 수준에서 구현할 수있는 기능에 대해 구체적으로 생각하고 있습니다. Boost는 실제로 (완벽한) 순방향 호환성 문제를 해결하지 않습니다. 내가 뭔가를 놓치지 않는 한 ...
mcmcc

Gcc 4.3에는 이미 소수의 C ++ 11 기능이 있으며 Rvalue-references가 아마도 가장 중요합니다.
Jan Hudec

@ JanHudec : 당신이 맞아요. 불쌍한 예. 어쨌든 구문을 지원하지 않는 다른 컴파일러가 있습니다 (예 : IBM의 C ++ 컴파일러 버전).
mcmcc

답변:


9

내 C ++ 프로그램에서 forwards- 및 이전 버전과의 호환성 수준을 유지하면서 나는 좋은 근무했습니다 나는 결국 그것에서 도서관 툴킷했습니다 때까지 , 나는 출시를 준비하고 있습니다를 이미 출시되었습니다. 일반적으로 구문이 아닌 기능 (일부 포워드 에뮬레이트 할 수 없음)에서 "완벽한"앞으로 호환성을 얻지 못한다는 사실을 받아들이는 한 (매크로를 사용해야합니다. 몇 가지) 당신은 모두 설정됩니다.

실제 사용하기에 충분한 수준으로 C ++ 03에서 에뮬레이션 할 수있는 많은 기능이 있으며 예를 들어 Boost와 함께 제공되는 번거 로움이 없습니다. 심지어 C ++ 표준 제안조차도 nullptrC ++ 03 백 포트 를 제안합니다. 그리고 예를 들어 C ++ 11은 있지만 몇 년 동안 미리 보았던 모든 것들에 대한 TR1이 있습니다. 뿐만 아니라 assert variant, transparent functors와 같은 일부 C ++ 14 기능 은 C ++ 03에서 구현 될 optional 있습니다!

내가 백 포트 할 수 없다는 것을 아는 유일한 것은 constexpr과 variadic 템플릿입니다.

네임 스페이스에 물건을 추가하는 전체 문제와 관련하여 std내 견해 는 전혀 중요하지 않다는 것입니다. 가장 중요하고 관련성이 높은 C ++ 라이브러리 중 하나 인 Boost와 TR1의 구현 인 Boost.Tr1을 생각해보십시오. C ++를 개선하고 C ++ 11과 호환되도록 전달하면 정의에 따라 C ++ 03 이 아닌 것으로 변환 하므로 피하거나 피하려는 표준을 통해 자신을 차단하는 것입니다. 간단히 말해서, 비생산적입니다. 순수 주의자들은 불평 할 것이지만, 정의상 그들에 대해 신경 쓸 필요는 없습니다.

물론, 당신이 결국 (03) 표준을 따르지 않는다고해서 시도하지 못하거나 기꺼이 그 표준을 어 기고 갈 것이라는 의미는 아닙니다 . 요점은 그것이 아니다. std네임 스페이스에 추가되는 내용에 대해 매우 신중하게 제어하고 소프트웨어가 사용되는 환경 (예 : 테스트 수행)을 제어하는 ​​한, 전혀 해를 끼치 지 않아야합니다. 가능하면 모든 네임 스페이스를 별도의 네임 스페이스에 정의 using하고 네임 스페이스 에 지시문 만 추가 std하면 "절대적으로"필요한 것 이상의 것을 추가 할 수 없습니다.


업데이트 (2013) : 원래 질문의 요청으로 담당자가 없기 때문에 추가 할 수없는 의견을 볼 때 C ++ 11 및 C ++ 14 기능과 이식성의 정도는 다음과 같습니다. C ++ 03으로 :

  • nullptr: 공식위원회의 백 포트를 감안할 때 완전히 구현 가능; 아마도 "기본"유형으로 인식되도록 type_traits 전문화를 제공해야 할 수도 있습니다.
  • forward_list: 할당 자 지원은 Tr1 구현이 제공 할 수있는 것에 의존하지만 완벽하게 구현할 수 있습니다.
  • 새로운 알고리즘 (partition_copy 등) : 완전히 구현 가능
  • 버팀대 시퀀스의 컨테이너 구성 (예 :) vector<int> v = {1, 2, 3, 4};: 원하는 것보다 완벽 하지만 완벽하게 구현할 수 있습니다.
  • static_assert: 매크로로 구현하면 거의 완벽하게 구현할 수 있습니다 (쉼표 만주의하면됩니다).
  • unique_ptr: 거의 완벽하게 구현 가능하지만 코드 호출 (콘테이너 등에 저장하기 위해)을 지원해야합니다. 아래를 참조하십시오.
  • rvalue-references : 얼마나 많은 것을 얻을 수 있는지에 따라 거의 완벽하게 구현할 수 있습니다 (예 : Boost Move).
  • Foreach 반복 : 거의 완벽하게 구현할 수있는 구문은 약간 다릅니다.
  • 로컬 함수를 인수로 사용 (예 : 변환) : 거의 완벽하게 구현 가능하지만 구문은 충분히 다릅니다. 예를 들어, 로컬 함수는 호출 사이트에서 정의되지 않고 바로 전에 정의됩니다.
  • 명시 적 변환 연산자 : 실제 수준으로 구현 가능 (변환을 명시 적으로 함), 불완전한 C ++ 의 "explicit_cast"를 참조하십시오 . 그러나 static_cast<>거의 불가능한 언어 기능과의 통합 .
  • 인수 전달 : 위의 rvalue-references에 대해 실제 수준으로 구현할 수 있지만 전달 가능한 인수를 사용하여 함수에 N 과부하를 제공해야합니다.
  • 이동 : 실제 수준으로 구현 가능 (위의 두 가지 참조). 물론,이를 활용하려면 수정 컨테이너와 객체를 사용해야합니다.
  • 범위가 지정된 할당 자 : Tr1 구현이 지원할 수 없다면 실제로 구현할 수 없습니다.
  • 멀티 바이트 문자 유형 : Tr1이 지원하지 않으면 실제로 구현할 수 없습니다. 그러나 의도 된 목적을 위해 C ++ 11을 사용 하더라도 ICU와 같은 문제를 처리하도록 특별히 설계된 라이브러리를 사용하는 것이 좋습니다 .
  • Variadic argument list : 번거롭고 실행 가능한 인수 전달에주의를 기울이십시오.
  • noexcept: 컴파일러의 기능에 따라 다릅니다.
  • 새로운 auto의미와 decltype:는 컴파일러의 기능에 따라 다릅니다-예 : __typeof__.
  • 크기 int16_t가 지정된 정수 유형 ( 등) : 컴파일러의 기능에 따라 다릅니다. 또는 Portable stdint.h에 위임 할 수 있습니다.
  • 유형 속성 : 컴파일러 기능에 따라 다릅니다.
  • 이니셜 라이저 목록 : 내 지식으로는 구현할 수 없습니다. 그러나 시퀀스를 사용하여 컨테이너를 초기화하려는 경우 위의 "컨테이너 구성"을 참조하십시오.
  • 템플릿 별칭 : 내 지식으로는 구현할 수 없지만 어쨌든 불필요한 기능 ::type이며 템플릿에서 영원히 사용했습니다.
  • 다양한 템플릿 : 내 지식으로는 구현할 수 없습니다. close는 템플릿 인수 기본값이며 N 전문화 등이 필요합니다.
  • constexpr: 내 지식으로는 구현할 수 없습니다.
  • 균일 한 초기화 : 내 지식 으로는 구현할 수 없지만 보장 된 기본 생성자 초기화는 부스트의 값 초기화로 구현할 수 있습니다.
  • C ++ 14 dynarray: 완벽하게 구현 가능
  • C ++ 14 optional<>: C ++ 03 컴파일러가 정렬 설정을 지원하는 한 거의 완벽하게 구현할 수 있습니다.
  • C ++ 14 투명 기능 : 거의 완벽하게 구현 가능하지만 클라이언트 코드는 명시 적으로 예를 들어 std::less<void>작동해야합니다.
  • C ++ 14의 새로운 어설 션 (예 : 변형 assure:) 완전히 대신 던져 당신이 사용하려는 경우 근처에-완벽하게 구현 가능, 주장하려면 구현 가능.
  • C ++ 14 튜플 확장 (타입별로 튜플 요소 가져 오기) : 완전히 구현 가능하며 기능 제안에 설명 된 정확한 경우로 컴파일하지 못할 수도 있습니다.

(면책 조항 : 이러한 기능 중 일부는 위에서 링크 한 C ++ 백 포트 라이브러리에서 구현되므로 "완전히"또는 "완전히"라고 말할 때 내가 말하는 것을 알고 있다고 생각합니다.


6

이것은 근본적으로 불가능합니다. 고려하십시오 std::unique_ptr<Thing>. rvalue 참조를 라이브러리로 에뮬레이트 할 수 있으면 언어 기능이 아닙니다.


1
나는 "가능한 어느 정도까지"라고 말했습니다. 분명히 일부 기능은 #ifdef 뒤에 남겨 두거나 전혀 사용하지 않아야합니다. std :: move ()는 구문을 지원할 수있는 기능입니다 (기능은 아님).
mcmcc

2
실제로 rvalue 참조 제안 에는 라이브러리 기반 솔루션이 언급되어 있습니다!
Jan Hudec

보다 구체적으로, C ++ 03에서 특정 클래스에 대한 이동 의미론을 구현할 수 있으므로이를 정의 할 수 있어야 std::unique_ptr하지만 rvalue 참조의 다른 기능은 C ++ 03에서 구현할 수 없으므로 std::forward불가능합니다. 다른 하나 std::unique_ptr는 컬렉션이 모두를 대체하지 않으면 컬렉션이 이동 의미를 사용하지 않기 때문에 유용하지 않다는 것입니다.
Jan Hudec

@ JanHudec : 정의 할 수 없습니다 unique_ptr. 의 실패를보십시오 auto_ptr. 언어 기능에 의해 기본적으로 의미가 활성화 된 클래스 unique_ptr교과서 예입니다.
DeadMG

@DeadMG : 아니요. unique_ptr기본적으로 언어 기능으로 활성화 된 것은 아닙니다 . 그래도 그 기능이 없으면별로 유용하지 않습니다. 완벽한 전달이 없으면 많은 경우에 사용할 수 없으며 완벽한 전달에는 해당 기능이 필요하기 때문입니다.
Jan Hudec

2
  1. Gcc는 4.3에서 C ++ 11 (그 당시 C ++ 0x)을 도입하기 시작했다. 이 테이블 에는 이미 rvalue 참조와 덜 사용되는 다른 기능이 있습니다 ( -std=c++0x활성화하려면 옵션을 지정 해야 함).
  2. C ++ 11의 표준 라이브러리에 대한 많은 추가 사항은 이미 TR1에 정의되어 있으며 GNU stdlibc ++는 std :: tr1 네임 스페이스로 제공합니다. 따라서 적절한 조건부 사용을 수행하십시오.
  3. Boost는 대부분의 TR1 함수를 정의하고 TR1 네임 스페이스에이를 삽입 할 수 있습니다 (하지만 GNU stdlibc ++를 사용하는 경우 VS2010과 gcc 4.3도 마찬가지 임).
  4. std네임 스페이스에 무엇이든 넣는 것은 "정의되지 않은 행동"입니다. 이는 사양에서 어떤 일이 일어날 지 말하지 않는다는 것을 의미합니다. 그러나 특정 플랫폼에서 표준 라이브러리가 무언가를 정의하지 않는 경우 계속 진행하여 정의하십시오. 각 플랫폼에서 필요한 것과 정의 할 수있는 것을 확인해야합니다.
  5. 를 rvalue 참조에 대한 제안, N1690은 03 C ++로 이동 의미를 구현하는 방법을 언급하고있다. 대체 할 수 있습니다 unique_ptr. 그러나 실제로 이동 의미를 사용하는 컬렉션에 의존하고 C ++ 03은 그렇지 않을 것이므로 너무 유용하지 않습니다.

1
GCC에 대해서는 맞지만 불행히도 다른 (GCC가 아닌) 컴파일러도 지원해야합니다. # 4 글 머리 기호는 내가 묻는 질문의 핵심입니다. # 5는 흥미롭지 만 이전 플랫폼에서는 이동 의미론 (복사 최적화)을 지원하지 않고 컴파일 가능한 구문으로 "std :: move ()"를 지원하려고합니다.
mcmcc
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.