나는 오래된 코드가 컴파일을 멈추게하는 C ++ 11의 적어도 하나의 변경 사항 : explicit operator bool()
표준 라이브러리에 도입 하여의 이전 인스턴스를 대체 한다는 것을 알고 있습니다 operator void*()
. 물론, 이것이 깨질 코드는 아마도 처음에는 유효하지 않은 코드 일 것입니다. 그럼에도 불구하고 여전히 중요한 변경 사항입니다.
다른 주요 변경 사항이 있습니까?
답변
FDIS에는 부록 C.2
“C ++ 및 ISO C ++ 2003” 에 비 호환성 섹션이 있습니다.
여기에서 FDIS를 해석하여 SO 답변으로 적합하게 만드는 요약. 차이점을 설명하기 위해 내 예제를 추가했습니다.
라이브러리의 비 호환성이 몇 가지 있지만 그 의미를 정확히 알지 못하므로 다른 사람들이 자세히 설명 할 수 있습니다.
핵심 언어
#define u8 "abc"
const char *s = u8"def"; // Previously "abcdef", now "def"
#define _x "there"
"hello"_x // now a user-defined-string-literal. Previously, expanded _x .
새 키워드 : alignas, alignof, char16_t, char32_t, constexpr, decltype, noexcept, nullptr, static_assert 및 thread_local
long으로 표현할 수있는 것보다 큰 특정 정수 리터럴은 부호없는 정수 유형에서 부호있는 long long으로 변경 될 수 있습니다.
정수 나누기를 사용하는 유효한 C ++ 2003 코드는 결과를 0 또는 음의 무한대로 반올림하지만 C ++ 0x는 항상 결과를 0으로 반올림합니다.
(실제로 대부분의 사람들에게 호환성 문제는 아닙니다).
키워드
auto
를 스토리지 클래스 지정자로 사용하는 유효한 C ++ 2003 코드 는 C ++ 0x에서 유효하지 않을 수 있습니다.
변환이 좁아지면 C ++ 03과 호환되지 않습니다. 예를 들어 다음 코드는 C ++ 2003에서는 유효하지만 double to int는 축소 변환이므로이 국제 표준에서는 유효하지 않습니다.
int x[] = { 2.0 };
암시 적으로 선언 된 특수 멤버 함수는 암시 적 정의의 형식이 잘못되었을 때 삭제 된 것으로 정의됩니다.
정의가 필요하지 않은 상황 (예 : 잠재적으로 평가되지 않은 설명)에서 이러한 특수 멤버 함수 중 하나를 사용하는 유효한 C ++ 2003 프로그램은 잘못 구성됩니다.
나에 의한 예 :
struct A { private: A(); };
struct B : A { };
int main() { sizeof B(); /* valid in C++03, invalid in C++0x */ }
이러한 크기의 트릭은 일부 SFINAE에서 사용되었으며 지금 변경해야합니다. 🙂
사용자 선언 소멸자는 암시 적 예외 사양이 있습니다.
나에 의한 예 :
struct A {
~A() { throw "foo"; }
};
int main() { try { A a; } catch(...) { } }
이 코드는 terminate
C ++ 0x에서 호출 하지만 C ++ 03에서는 호출 되지 않습니다. A::~A
C ++ 0x에서 의 암시 적 예외 사양은 입니다 noexcept(true)
.
포함 된 유효한 C ++ 2003 선언
export
은 C ++ 0x에서 잘못 구성되었습니다.
유효한 C ++ 2003 표현식
>
뒤에 바로 다른 표현식이 포함 되어>
이제는 두 개의 템플리트를 닫는 것으로 간주 될 수 있습니다.
C ++ 03에서는 >>
항상 shift-operator 토큰이됩니다.
내부 연결로 함수의 종속 호출을 허용합니다.
나에 의한 예 :
static void f(int) { }
void f(long) { }
template<typename T>
void g(T t) { f(t); }
int main() { g(0); }
C ++ 03에서는을 호출 f(long)
하지만 C ++ 0x에서는을 호출합니다 f(int)
. C ++ 03 및 C ++ 0x에서 다음 호출이 있습니다 f(B)
(인스턴스화 컨텍스트는 여전히 extern linkage 선언 만 고려합니다).
struct B { };
struct A : B { };
template<typename T>
void g(T t) { f(t); }
static void f(A) { }
void f(B) { }
int main() { A a; g(a); }
f(A)
외부 연결이 없기 때문에 더 나은 일치 가 이루어지지 않습니다.
라이브러리 변경
C ++ 0x의 C ++ 표준 라이브러리에 추가 된 식별자를 사용하는 유효한 C ++ 2003 코드는이 국제 표준에서 컴파일 또는 다른 결과를 생성하지 못할 수 있습니다.
#includes
새로운 C ++ 0x 표준 라이브러리 헤더의 이름을 가진 헤더가이 국제 표준에서 유효하지 않은 유효한 C ++ 2003 코드 .
스왑이있을 것으로 예상되어 컴파일 된 유효한 C ++ 2003 코드는
<algorithm>
다음을 포함해야합니다.<utility>
글로벌 네임 스페이스
posix
는 이제 표준화를 위해 예약되어 있습니다.
유효한 C ++가 정의하는 것이 2003 코드
override
,final
,carries_dependency
, 또는noreturn
매크로와 같은 C ++ 0X에 유효하지 않습니다.
답변
자동 키워드의 의미가 변경되었습니다.
답변
변화를 깨고?
당신이 사용하는 경우 음, 한 가지, decltype
, constexpr
, nullptr
, 등의 식별자로 당신은 문제가 될 수 있습니다 …
답변
비 호환성 섹션에서 다루지 않는 일부 핵심 비 호환성 :
C ++ 0x는 이름이 템플리트 템플리트 매개 변수에 대한 인수로 전달되고 템플리트 유형 매개 변수에 전달 된 경우 유형으로 삽입 된 클래스 이름을 템플리트로 처리합니다.
이러한 시나리오에서 삽입 된 클래스 이름을 항상 유형으로 사용하는 경우 유효한 C ++ 03 코드가 다르게 작동 할 수 있습니다. 내 clang PR에서 가져온 예제 코드
template<template<typename> class X>
struct M { };
template<template<typename> class X>
void g(int = 0); // #1
template<typename T>
void g(long = 0); // #2
template<typename T>
struct A {
void f() {
g<A>(); /* is ambiguous in C++0x */
g<A>(1); /* should choose #1 in C++0x */
}
};
void h() {
A<int> a;
a.f();
}
C ++ 03에서 코드는 두 번째를 g
두 번 호출합니다 .
C ++ 0x는 C ++ 03에 종속 된 일부 이름을 이제 비 종속으로 만듭니다. 또한 인스턴스화시 반복 될 현재 클래스 템플릿의 멤버를 참조하는 비 의존적 정규화 된 이름에 대한 이름 조회가 필요하며 이러한 이름이 템플릿 정의 컨텍스트에서 수행 된 것과 동일한 방식으로 조회되는지 확인해야합니다.
이 규칙으로 인해 지배 규칙에 의존하는 유효한 C ++ 03 코드가 더 이상 컴파일되지 않을 수 있습니다.
예:
struct B { void f(); };
template<typename T>
struct A : virtual B { void f(); };
template<typename T>
struct C : virtual B, A<T> {
void g() { this->f(); }
};
int main() { C<int> c; c.g(); }
이 유효한 C ++ 03 코드 A<int>::f
는 C ++ 0x에서 유효하지 않습니다. 인스턴스화 할 때 이름 조회가 A<int>::f
와 반대로 발견 되어 B::f
정의 조회와 충돌이 발생하기 때문입니다.
이 시점에서 이것이 FDIS의 결함인지 확실하지 않습니다. 위원회는이를 알고 있으며 상황을 평가할 것입니다.
마지막 부분이 기본 클래스를 나타내는 규정 된 이름의 규정 자의 마지막 부분에있는 식별자와 동일한 사용 선언은 선언을 사용하여 해당 이름의 멤버 대신 생성자의 이름을 지정합니다.
예:
struct A { protected: int B; };
typedef A B;
struct C : B {
// inheriting constructor, instead of bringing A::B into scope
using B::B;
};
int main() { C c; c.B = 0; }
위의 예제 코드는 C ++ 03에서는 잘 구성되어 있지만 C ++ 0x에서는 잘못 구성 A::B
되어 main
있습니다.
답변
스트림 추출 실패는 다르게 처리됩니다.
예
#include <sstream>
#include <cassert>
int main()
{
std::stringstream ss;
ss << '!';
int x = -1;
assert(!(ss >> x)); // C++03 and C++11
assert(x == -1); // C++03
assert(x == 0); // C++11
}
제안 변경
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2011/n3246.html#23
표준 참조
[C++03: 22.2.2.1.2/11]:
2 단계 처리 결과는 다음 중 하나 일 수 있습니다.
- 2 단계에서 일련의 문자가 누적되어 (의 규칙에 따라
scanf
) 유형의 값으로 변환val
됩니다. 이 값은에 저장val
되고ios_base::goodbit
에 저장됩니다err
.- 2 단계에서 누적 된 문자 순서로 인해
scanf
입력 오류가보고되었을 수 있습니다.ios_base::failbit
에 할당되어err
있습니다. [ed :에 저장된 것이 없습니다val
.]
[C++11: 22.4.2.1.2/3]:
[..] 저장할 숫자 값은 다음 중 하나 일 수 있습니다.
- 변환 함수가 전체 필드를 변환하지 못하면 0입니다 .
ios_base::failbit
에 할당되어err
있습니다.- 필드 값이 너무 큰 양성을 나타내는 경우 가장 긍정적 표현할 값은로 표현된다
val
.ios_base::failbit
에 할당되어err
있습니다.- 필드가로 표현하기에 너무 큰 음수를 나타내는 경우 부호가없는 정수 유형에 대해 가장 음의 표현 가능 값 또는 0
val
.ios_base::failbit
에 할당되어err
있습니다.- 그렇지 않으면 변환 된 값
결과 숫자 값은
val
.
구현
-
C ++ 11에 대한 GCC 4.8의 올바른 출력 .
어설 션`x == -1 ‘실패
-
C ++ 03에 대한 GCC 4.5-4.8 모든 출력 는 다음과 같습니다. 버그로 보입니다.
어설 션`x == -1 ‘실패
-
Visual C ++ 2008 ExpressC ++ 03에 대해 올바르게 출력됩니다.
어설 션 실패 : x == 0
-
Visual C ++ 2012 Express 가 C ++ 11에 대해 잘못 출력되어 구현 상태 문제인 것으로 보입니다.
어설 션 실패 : x == 0
답변
명시 적 변환 연산자를 도입하면 어떤 변화가 있습니까? 이전 버전은 여전히 이전과 마찬가지로 “유효”합니다.
예에서에서 operator void*() const
로의 변경은 explicit operator bool() const
끊임없는 변경이 될 수 있지만 그 자체로 잘못된 방식으로 사용되는 경우에만 가능합니다. 적합한 코드는 깨지지 않습니다.
이제 또 다른 주요 변경 사항은 집계 초기화 중에 축소 변환을 금지하는 것입니다 .
int a[] = { 1.0 }; // error
편집 : 기억하기 만하면 std::identity<T>
C ++ 0x에서 제거됩니다 (주 참조). 유형을 종속시키는 편리한 구조체입니다. 구조체는 실제로 많은 일을하지 않기 때문에 수정해야합니다.
template<class T>
struct identity{
typedef T type;
};
답변
더 효율적인 코드를 허용하지만 몇 가지 경우에 대해 이전 버전과의 호환성을 자동으로 깨뜨리는 컨테이너 라이브러리에는 수많은 변경이 있습니다.