Consider these code snippets:
Version (1)
void q() {}
class B {
void f() noexcept(noexcept(q())) {q(); }
decltype(&B::f) f2;
};
Version (2)
void q() {}
class B {
void f() noexcept(true) {q(); }
decltype(&B::f) f2;
};
Version (3)
void q() {}
class B {
void f() noexcept {q(); }
decltype(&B::f) f2;
};
All versions of GCC compile these code snippets without any error or warning (including trunk-version). All versions of Clang which support C++17 deny version (1) and (2), but not version (3), with the following error:
<source>:4:16: error: exception specification is not available until end of class definition
decltype(&B::f) f2;
^
Take into account that the standard defines noexcept as equivalent to noexcept(true) [except.spec]. Thus, version (2) and version(3) should be equivalent, which they are not for clang.
Thus, the following questions: At which point do exception specifications need to be evaluated according to C++17 standards? And, if some codes above are invalid, what is the rational behind?
Abstract background for those who are interested:
template <typename F>
struct result_type;
template<typename R, typename C, typename... Args>
struct result_type<R(C::*)(Args...)> {
using type = R;
}; // there may be other specializations ...
class B {
int f() noexcept(false) { return 3; }
typename result_type<decltype(&B::f)>::type a;
};
This code should be valid at least up to C++ 14, because noexcept was not part of the function type (for clang, it compiled up to version 3.9.1). For C++ 17, there is no way to do this.
This is a result of CWG 1330.
Basically, the class is considered to be complete within its noexcept-specifier (in the resolution of the defect above it's referred to as an exception-specification).
This puts us in a situation where:
void q() {}
class B {
void f() noexcept(noexcept(q())) {q(); }
// ~~~~~~~~~~~~~
// evaluated in the context of complete B
decltype(&B::f) f2;
//~~~~~~~~~~~~~~~
//cannot wait until B is complete to evaluate
};
We need to know decltype(&B::f) to process the declaration of B::f2, but in order to know that type, we need to know the what the noexcept-specifier of B::f is (because now that's part of the type system), but in order to do that, we need to evaluate the noexcept-specifier in the context of the complete B.
The program is ill-formed, clang is correct.
I will answer this question myself with references to all relevant resources.
Let me cite Richard Smith to argue why this is a defect, and why all of the examples are ill-formed, because exception specification are only parsed at the end of the class.
Clang is approximately correct to reject that code.
Per C++ DR1330, exception specifications are not parsed until we reach the end of the class (they can name class members that are declared later, and the class is complete within them), just like member function bodies, default member initializers, and default arguments.
Finally, there's C++ DR361 (still open 16 years after being filed, sadly), wherein the conclusion of CWG is that the program is ill-formed if you use a delay-parsed construct before the end of the class. But we don't have actual standards wording to back that up yet, just a standard that's unimplementable without a fix to that defect.
LLVM Bug 37559, but also see Google Groups, CWG 361, CWG 1330
Further, noexcept should in principal be completely equivalent to noexcept(true), as stated in [except.spec], and it is clearly wrong to accept noexcept, but deny noexcept(true).
Thus, the conclusion is that all examples are ill-formed, even though that is not the desired behavior.
Related
There appears to be some discrepancy between compilers as to whether the following code is well formed.
In particular, GCC and Clang accept this code -- whereas MSVC rejects it:
template <typename T>
class Bar{};
template <typename T>
struct Foo
{
using element_type = T;
operator Bar<element_type>();
};
template <typename T>
Foo<T>::operator Bar<element_type>()
{
return {};
}
MSVC's rejection message is just a generic:
<source>(11): error C2065: 'element_type': undeclared identifier
The issue only appears to occur when the template argument for the conversion type is a dependent template type, since this is resolved by changing Bar<element_type> to either Bar<T> or Bar<typename Foo<T>::element_type>. I've made a small example on compiler explorer to demonstrate this. This appears to occur from C++11 (possibly older, didn't test) up to C++2a, and is independent of the compiler's versions or flags.
I know that C++ allows dropping the prefixing class-name specifier for types when in the body or parameter list of a class function/constructor definition -- but I'm unsure whether this same short-form is allowed when handling a conversion operator in an out-of-line definition.
Is this an ambiguity in the standard, or a bug in either of the compilers? I'm mostly curious to know how this is defined (or not, as it may be) in the C++ standard.
Edit: To add to the confusion, it appears that MSVC accepts the following code:
template <typename T>
struct Foo
{
using element_type = T;
operator element_type();
};
template <typename T>
Foo<T>::operator element_type() // note: no 'typename' syntax
{
return {};
}
so this doesn't appear to be just an issue caused from conversion to template-dependent type names... I'm suspecting this may be an MSVC bug rather than a discrepancy.
The standard is very vague on the subject. In the case where you're explicitly calling a conversion function (a.operator int()), [basic.lookup.classref]/7 says
If the id-expression is a conversion-function-id, its conversion-type-id is first looked up in the class of the object expression ([class.member.lookup]) and the name, if found, is used.
Unfortunately, a conversion-type-id can have any number of names (including 0), in which case it is impossible to look up directly. [class.qual]/1.2 applies the same non-rule to references to the function using ::, which may or may not apply to out-of-class definitions of such functions (since normal lookup doesn't apply there).
There is massive implementation divergence. In the following example, the comments indicate which compilers (the most current versions at the moment on Compiler Explorer) reject which lines (usually because they can't find the name):
struct X {
struct A {};
operator A();
template<class> struct B {};
using C = int;
operator B<C>();
struct D {using I=int; I i;};
operator int D::*();
operator D::I();
static float E;
operator decltype(E)();
struct G {};
operator struct G();
};
X::operator A() {throw;} // OK
X::operator B<C>() {throw;} // MSVC: B and C
X::operator int D::*() {throw;} // MSVC
X::operator D::I() {throw;} // MSVC
X::operator decltype(E)() {throw;} // MSVC
X::operator struct G() {throw;} // MSVC thinks G is ::G
void f(X x) {
x.operator A(); // Clang, MSVC
x.operator B<C>(); // GCC, Clang, ICC: C; MSVC: B and C
x.operator int D::*(); // Clang
x.operator D::I(); // Clang
x.operator decltype(E)(); // Clang, ICC, MSVC; GCC segfaults
x.operator struct G(); // GCC, Clang, MSVC think G is local to f
}
Clang accepts all the definitions and rejects all the calls because it doesn't implement [basic.lookup.classref]/7 at all but helpfully misapplies [basic.scope.class]/4 within the declarator-id when it is a conversion-function-id.
New rules are in process to clarify this mess (along with many other messes); exactly how many of the above should be accepted is currently being discussed as part of reviewing that paper. My opinion is that GCC's behavior is closest to what is desired (aside from the ICE, of course).
I know that at least one of the changes in C++11 that will cause some old code to stop compiling: the introduction of explicit operator bool() in the standard library, replacing old instances of operator void*(). Granted, the code that this will break is probably code that should not have been valid in the first place, but it's still a breaking change nonetheless: programs that used to be valid no longer are.
Are there any other breaking changes?
The FDIS has a section for incompatibilities, at appendix C.2 "C++ and ISO C++ 2003".
Summary, paraphrasing the FDIS here, to make it (better) suitable as a SO answer. I added some examples of my own to illustrate the differences.
There are a few library-related incompatibilities where I don't exactly know the implications of, so I leave those for others to elaborate on.
Core language
#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 .
New keywords: alignas, alignof, char16_t, char32_t, constexpr, decltype, noexcept, nullptr, static_assert, and thread_local
Certain integer literals larger than can be represented by long could change from an unsigned integer type to signed long long.
Valid C++ 2003 code that uses integer division rounds the result toward 0 or toward negative infinity, whereas C++0x always rounds the result toward 0.
(admittedly not really a compatibility problem for most people).
Valid C++ 2003 code that uses the keyword auto as a storage class specifier may be invalid in C++0x.
Narrowing conversions cause incompatibilities with C++03. For example, the following code is valid in C++ 2003 but invalid in this International Standard because double to int is a narrowing conversion:
int x[] = { 2.0 };
Implicitly-declared special member functions are defined as deleted when the implicit definition would have been ill-formed.
A valid C++ 2003 program that uses one of these special member functions in a context where the definition is not required (e.g., in an expresion that is not potentially evaluated) becomes ill-formed.
Example by me:
struct A { private: A(); };
struct B : A { };
int main() { sizeof B(); /* valid in C++03, invalid in C++0x */ }
Such sizeof tricks have been used by some SFINAE, and needs to be changed now :)
User-declared destructors have an implicit exception specification.
Example by me:
struct A {
~A() { throw "foo"; }
};
int main() { try { A a; } catch(...) { } }
This code calls terminate in C++0x, but does not in C++03. Because the implicit exception specification of A::~A in C++0x is noexcept(true).
A valid C++ 2003 declaration containing export is ill-formed in C++0x.
A valid C++ 2003 expression containing > followed immediately by another > may now be treated as closing two templates.
In C++03, >> would always be the shift-operator token.
Allow dependent calls of functions with internal linkage.
Example by me:
static void f(int) { }
void f(long) { }
template<typename T>
void g(T t) { f(t); }
int main() { g(0); }
In C++03, this calls f(long), but in C++0x, this calls f(int). It should be noted that in both C++03 and C++0x, the following calls f(B) (the instantiation context still only considers extern linkage declarations).
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); }
The better matching f(A) is not taken, because it does not have external linkage.
Library changes
Valid C++ 2003 code that uses any identifiers added to the C++ standard
library of C++0x may fail to compile or produce different results in This International Standard.
Valid C++ 2003 code that #includes headers with names of new C++0x standard library headers may be invalid in this International Standard.
Valid C++ 2003 code that has been compiled expecting swap to be in <algorithm> may have to instead include <utility>
The global namespace posix is now reserved for standardization.
Valid C++ 2003 code that defines override, final, carries_dependency, or noreturn as macros is invalid in C++0x.
The meaning of the auto keyword changed.
Breaking change?
Well, for one thing, if you used decltype, constexpr, nullptr, etc. as identifiers then you may be in trouble...
Some core incompatibilities that are not covered by the incompatibilities section:
C++0x treats the injected class name as a template, if the name is passed as an argument to a template template parameter, and as a type if it is passed to a template type parameter.
Valid C++03 code may behave differently if it relies on the injected class name to be always a type in these scenarios. Example code taken from my 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();
}
In C++03, the code calls the second g both times.
C++0x makes some names that were dependent in C++03 to be now non-dependent. And requires name lookup for non-dependent qualified names that refer to members of the current class template to be repeated at instantiation, and requires verification that these names lookup the same way as done at the template definition context.
Valid C++03 code that depends on the dominance rule may now not compile anymore because of this change.
Example:
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(); }
This valid C++03 code that calls A<int>::f is not valid in C++0x, because name lookup when instantiating will find A<int>::f as opposed to B::f, causing a conflict with the at-definition lookup.
At this point, it is not clear whether that is a defect in the FDIS. The committee is aware of this and will evaluate the situation.
A using declaration where the last part is the same as the identifier in the last part of the qualifier in the qualified name denoting a base class, that using declaration now names the constructor, instead of members with that name.
Example:
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; }
The above example code is well-formed in C++03, but ill-formed in C++0x, as A::B is still inaccessible in main.
Stream extraction failure is treated differently.
Example
#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
}
Change proposal
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2011/n3246.html#23
Standard reference
[C++03: 22.2.2.1.2/11]: The result of stage 2 processing can be one of
A sequence of chars has been accumulated in stage 2 that is converted (according to the rules of scanf) to a value of the type of val. This value is stored in val and ios_base::goodbit is stored in err.
The sequence of chars accumulated in stage 2 would have caused scanf to report an input failure. ios_base::failbit is assigned to err. [ed: Nothing is stored in val.]
[C++11: 22.4.2.1.2/3]: [..] The numeric value to be stored can be one of:
zero, if the conversion function fails to convert the entire field. ios_base::failbit is assigned to err.
the most positive representable value, if the field represents a value too large positive to be represented in val. ios_base::failbit is assigned to err.
the most negative representable value or zero for an unsigned integer type, if the field represents a value too large negative to be represented in val. ios_base::failbit is assigned to err.
the converted value, otherwise.
The resultant numeric value is stored in val.
Implementations
GCC 4.8 correctly outputs for C++11:
Assertion `x == -1' failed
GCC 4.5-4.8 all output for C++03 the following, which would appear to be a bug:
Assertion `x == -1' failed
Visual C++ 2008 Express correctly outputs for C++03:
Assertion failed: x == 0
Visual C++ 2012 Express incorrectly outputs for C++11, which would appear to be a status-of-implementation issue:
Assertion failed: x == 0
How is the introduction of explicit conversion operators a breaking change? The old version will still just be as "valid" as before.
Yes, the change from operator void*() const to explicit operator bool() const will be a breaking change, but only if it is used in a way that is wrong in and out of itself. Conforming code won't be broken.
Now, another breaking change is the banning of narrowing conversions during aggregate initialization:
int a[] = { 1.0 }; // error
Edit: Just rememberer, std::identity<T> will be removed in C++0x (see the note). It's a convenience struct to make types dependent. Since the struct really doesn't do much, this should fix it:
template<class T>
struct identity{
typedef T type;
};
There are numerous changes to the containers library that allow more efficient code but silently break backwards compatibility for a few corner cases.
Consider, for example, std::vector, default construction, C++0x, and breaking changes.
There's been a lot of discussion of implicit move breaking backward compatibility
(an older page with relevant discussion)
If you read down into the comments, implicit move return is also a breaking change.
struct x {
x(int) {}
};
void f(auto x = 3) { }
int main() {
f();
}
C++03: valid.
C++0x: error: parameter declared 'auto'
I know that at least one of the changes in C++11 that will cause some old code to stop compiling: the introduction of explicit operator bool() in the standard library, replacing old instances of operator void*(). Granted, the code that this will break is probably code that should not have been valid in the first place, but it's still a breaking change nonetheless: programs that used to be valid no longer are.
Are there any other breaking changes?
The FDIS has a section for incompatibilities, at appendix C.2 "C++ and ISO C++ 2003".
Summary, paraphrasing the FDIS here, to make it (better) suitable as a SO answer. I added some examples of my own to illustrate the differences.
There are a few library-related incompatibilities where I don't exactly know the implications of, so I leave those for others to elaborate on.
Core language
#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 .
New keywords: alignas, alignof, char16_t, char32_t, constexpr, decltype, noexcept, nullptr, static_assert, and thread_local
Certain integer literals larger than can be represented by long could change from an unsigned integer type to signed long long.
Valid C++ 2003 code that uses integer division rounds the result toward 0 or toward negative infinity, whereas C++0x always rounds the result toward 0.
(admittedly not really a compatibility problem for most people).
Valid C++ 2003 code that uses the keyword auto as a storage class specifier may be invalid in C++0x.
Narrowing conversions cause incompatibilities with C++03. For example, the following code is valid in C++ 2003 but invalid in this International Standard because double to int is a narrowing conversion:
int x[] = { 2.0 };
Implicitly-declared special member functions are defined as deleted when the implicit definition would have been ill-formed.
A valid C++ 2003 program that uses one of these special member functions in a context where the definition is not required (e.g., in an expresion that is not potentially evaluated) becomes ill-formed.
Example by me:
struct A { private: A(); };
struct B : A { };
int main() { sizeof B(); /* valid in C++03, invalid in C++0x */ }
Such sizeof tricks have been used by some SFINAE, and needs to be changed now :)
User-declared destructors have an implicit exception specification.
Example by me:
struct A {
~A() { throw "foo"; }
};
int main() { try { A a; } catch(...) { } }
This code calls terminate in C++0x, but does not in C++03. Because the implicit exception specification of A::~A in C++0x is noexcept(true).
A valid C++ 2003 declaration containing export is ill-formed in C++0x.
A valid C++ 2003 expression containing > followed immediately by another > may now be treated as closing two templates.
In C++03, >> would always be the shift-operator token.
Allow dependent calls of functions with internal linkage.
Example by me:
static void f(int) { }
void f(long) { }
template<typename T>
void g(T t) { f(t); }
int main() { g(0); }
In C++03, this calls f(long), but in C++0x, this calls f(int). It should be noted that in both C++03 and C++0x, the following calls f(B) (the instantiation context still only considers extern linkage declarations).
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); }
The better matching f(A) is not taken, because it does not have external linkage.
Library changes
Valid C++ 2003 code that uses any identifiers added to the C++ standard
library of C++0x may fail to compile or produce different results in This International Standard.
Valid C++ 2003 code that #includes headers with names of new C++0x standard library headers may be invalid in this International Standard.
Valid C++ 2003 code that has been compiled expecting swap to be in <algorithm> may have to instead include <utility>
The global namespace posix is now reserved for standardization.
Valid C++ 2003 code that defines override, final, carries_dependency, or noreturn as macros is invalid in C++0x.
The meaning of the auto keyword changed.
Breaking change?
Well, for one thing, if you used decltype, constexpr, nullptr, etc. as identifiers then you may be in trouble...
Some core incompatibilities that are not covered by the incompatibilities section:
C++0x treats the injected class name as a template, if the name is passed as an argument to a template template parameter, and as a type if it is passed to a template type parameter.
Valid C++03 code may behave differently if it relies on the injected class name to be always a type in these scenarios. Example code taken from my 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();
}
In C++03, the code calls the second g both times.
C++0x makes some names that were dependent in C++03 to be now non-dependent. And requires name lookup for non-dependent qualified names that refer to members of the current class template to be repeated at instantiation, and requires verification that these names lookup the same way as done at the template definition context.
Valid C++03 code that depends on the dominance rule may now not compile anymore because of this change.
Example:
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(); }
This valid C++03 code that calls A<int>::f is not valid in C++0x, because name lookup when instantiating will find A<int>::f as opposed to B::f, causing a conflict with the at-definition lookup.
At this point, it is not clear whether that is a defect in the FDIS. The committee is aware of this and will evaluate the situation.
A using declaration where the last part is the same as the identifier in the last part of the qualifier in the qualified name denoting a base class, that using declaration now names the constructor, instead of members with that name.
Example:
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; }
The above example code is well-formed in C++03, but ill-formed in C++0x, as A::B is still inaccessible in main.
Stream extraction failure is treated differently.
Example
#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
}
Change proposal
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2011/n3246.html#23
Standard reference
[C++03: 22.2.2.1.2/11]: The result of stage 2 processing can be one of
A sequence of chars has been accumulated in stage 2 that is converted (according to the rules of scanf) to a value of the type of val. This value is stored in val and ios_base::goodbit is stored in err.
The sequence of chars accumulated in stage 2 would have caused scanf to report an input failure. ios_base::failbit is assigned to err. [ed: Nothing is stored in val.]
[C++11: 22.4.2.1.2/3]: [..] The numeric value to be stored can be one of:
zero, if the conversion function fails to convert the entire field. ios_base::failbit is assigned to err.
the most positive representable value, if the field represents a value too large positive to be represented in val. ios_base::failbit is assigned to err.
the most negative representable value or zero for an unsigned integer type, if the field represents a value too large negative to be represented in val. ios_base::failbit is assigned to err.
the converted value, otherwise.
The resultant numeric value is stored in val.
Implementations
GCC 4.8 correctly outputs for C++11:
Assertion `x == -1' failed
GCC 4.5-4.8 all output for C++03 the following, which would appear to be a bug:
Assertion `x == -1' failed
Visual C++ 2008 Express correctly outputs for C++03:
Assertion failed: x == 0
Visual C++ 2012 Express incorrectly outputs for C++11, which would appear to be a status-of-implementation issue:
Assertion failed: x == 0
How is the introduction of explicit conversion operators a breaking change? The old version will still just be as "valid" as before.
Yes, the change from operator void*() const to explicit operator bool() const will be a breaking change, but only if it is used in a way that is wrong in and out of itself. Conforming code won't be broken.
Now, another breaking change is the banning of narrowing conversions during aggregate initialization:
int a[] = { 1.0 }; // error
Edit: Just rememberer, std::identity<T> will be removed in C++0x (see the note). It's a convenience struct to make types dependent. Since the struct really doesn't do much, this should fix it:
template<class T>
struct identity{
typedef T type;
};
There are numerous changes to the containers library that allow more efficient code but silently break backwards compatibility for a few corner cases.
Consider, for example, std::vector, default construction, C++0x, and breaking changes.
There's been a lot of discussion of implicit move breaking backward compatibility
(an older page with relevant discussion)
If you read down into the comments, implicit move return is also a breaking change.
struct x {
x(int) {}
};
void f(auto x = 3) { }
int main() {
f();
}
C++03: valid.
C++0x: error: parameter declared 'auto'
I know that at least one of the changes in C++11 that will cause some old code to stop compiling: the introduction of explicit operator bool() in the standard library, replacing old instances of operator void*(). Granted, the code that this will break is probably code that should not have been valid in the first place, but it's still a breaking change nonetheless: programs that used to be valid no longer are.
Are there any other breaking changes?
The FDIS has a section for incompatibilities, at appendix C.2 "C++ and ISO C++ 2003".
Summary, paraphrasing the FDIS here, to make it (better) suitable as a SO answer. I added some examples of my own to illustrate the differences.
There are a few library-related incompatibilities where I don't exactly know the implications of, so I leave those for others to elaborate on.
Core language
#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 .
New keywords: alignas, alignof, char16_t, char32_t, constexpr, decltype, noexcept, nullptr, static_assert, and thread_local
Certain integer literals larger than can be represented by long could change from an unsigned integer type to signed long long.
Valid C++ 2003 code that uses integer division rounds the result toward 0 or toward negative infinity, whereas C++0x always rounds the result toward 0.
(admittedly not really a compatibility problem for most people).
Valid C++ 2003 code that uses the keyword auto as a storage class specifier may be invalid in C++0x.
Narrowing conversions cause incompatibilities with C++03. For example, the following code is valid in C++ 2003 but invalid in this International Standard because double to int is a narrowing conversion:
int x[] = { 2.0 };
Implicitly-declared special member functions are defined as deleted when the implicit definition would have been ill-formed.
A valid C++ 2003 program that uses one of these special member functions in a context where the definition is not required (e.g., in an expresion that is not potentially evaluated) becomes ill-formed.
Example by me:
struct A { private: A(); };
struct B : A { };
int main() { sizeof B(); /* valid in C++03, invalid in C++0x */ }
Such sizeof tricks have been used by some SFINAE, and needs to be changed now :)
User-declared destructors have an implicit exception specification.
Example by me:
struct A {
~A() { throw "foo"; }
};
int main() { try { A a; } catch(...) { } }
This code calls terminate in C++0x, but does not in C++03. Because the implicit exception specification of A::~A in C++0x is noexcept(true).
A valid C++ 2003 declaration containing export is ill-formed in C++0x.
A valid C++ 2003 expression containing > followed immediately by another > may now be treated as closing two templates.
In C++03, >> would always be the shift-operator token.
Allow dependent calls of functions with internal linkage.
Example by me:
static void f(int) { }
void f(long) { }
template<typename T>
void g(T t) { f(t); }
int main() { g(0); }
In C++03, this calls f(long), but in C++0x, this calls f(int). It should be noted that in both C++03 and C++0x, the following calls f(B) (the instantiation context still only considers extern linkage declarations).
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); }
The better matching f(A) is not taken, because it does not have external linkage.
Library changes
Valid C++ 2003 code that uses any identifiers added to the C++ standard
library of C++0x may fail to compile or produce different results in This International Standard.
Valid C++ 2003 code that #includes headers with names of new C++0x standard library headers may be invalid in this International Standard.
Valid C++ 2003 code that has been compiled expecting swap to be in <algorithm> may have to instead include <utility>
The global namespace posix is now reserved for standardization.
Valid C++ 2003 code that defines override, final, carries_dependency, or noreturn as macros is invalid in C++0x.
The meaning of the auto keyword changed.
Breaking change?
Well, for one thing, if you used decltype, constexpr, nullptr, etc. as identifiers then you may be in trouble...
Some core incompatibilities that are not covered by the incompatibilities section:
C++0x treats the injected class name as a template, if the name is passed as an argument to a template template parameter, and as a type if it is passed to a template type parameter.
Valid C++03 code may behave differently if it relies on the injected class name to be always a type in these scenarios. Example code taken from my 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();
}
In C++03, the code calls the second g both times.
C++0x makes some names that were dependent in C++03 to be now non-dependent. And requires name lookup for non-dependent qualified names that refer to members of the current class template to be repeated at instantiation, and requires verification that these names lookup the same way as done at the template definition context.
Valid C++03 code that depends on the dominance rule may now not compile anymore because of this change.
Example:
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(); }
This valid C++03 code that calls A<int>::f is not valid in C++0x, because name lookup when instantiating will find A<int>::f as opposed to B::f, causing a conflict with the at-definition lookup.
At this point, it is not clear whether that is a defect in the FDIS. The committee is aware of this and will evaluate the situation.
A using declaration where the last part is the same as the identifier in the last part of the qualifier in the qualified name denoting a base class, that using declaration now names the constructor, instead of members with that name.
Example:
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; }
The above example code is well-formed in C++03, but ill-formed in C++0x, as A::B is still inaccessible in main.
Stream extraction failure is treated differently.
Example
#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
}
Change proposal
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2011/n3246.html#23
Standard reference
[C++03: 22.2.2.1.2/11]: The result of stage 2 processing can be one of
A sequence of chars has been accumulated in stage 2 that is converted (according to the rules of scanf) to a value of the type of val. This value is stored in val and ios_base::goodbit is stored in err.
The sequence of chars accumulated in stage 2 would have caused scanf to report an input failure. ios_base::failbit is assigned to err. [ed: Nothing is stored in val.]
[C++11: 22.4.2.1.2/3]: [..] The numeric value to be stored can be one of:
zero, if the conversion function fails to convert the entire field. ios_base::failbit is assigned to err.
the most positive representable value, if the field represents a value too large positive to be represented in val. ios_base::failbit is assigned to err.
the most negative representable value or zero for an unsigned integer type, if the field represents a value too large negative to be represented in val. ios_base::failbit is assigned to err.
the converted value, otherwise.
The resultant numeric value is stored in val.
Implementations
GCC 4.8 correctly outputs for C++11:
Assertion `x == -1' failed
GCC 4.5-4.8 all output for C++03 the following, which would appear to be a bug:
Assertion `x == -1' failed
Visual C++ 2008 Express correctly outputs for C++03:
Assertion failed: x == 0
Visual C++ 2012 Express incorrectly outputs for C++11, which would appear to be a status-of-implementation issue:
Assertion failed: x == 0
How is the introduction of explicit conversion operators a breaking change? The old version will still just be as "valid" as before.
Yes, the change from operator void*() const to explicit operator bool() const will be a breaking change, but only if it is used in a way that is wrong in and out of itself. Conforming code won't be broken.
Now, another breaking change is the banning of narrowing conversions during aggregate initialization:
int a[] = { 1.0 }; // error
Edit: Just rememberer, std::identity<T> will be removed in C++0x (see the note). It's a convenience struct to make types dependent. Since the struct really doesn't do much, this should fix it:
template<class T>
struct identity{
typedef T type;
};
There are numerous changes to the containers library that allow more efficient code but silently break backwards compatibility for a few corner cases.
Consider, for example, std::vector, default construction, C++0x, and breaking changes.
There's been a lot of discussion of implicit move breaking backward compatibility
(an older page with relevant discussion)
If you read down into the comments, implicit move return is also a breaking change.
struct x {
x(int) {}
};
void f(auto x = 3) { }
int main() {
f();
}
C++03: valid.
C++0x: error: parameter declared 'auto'
I know that at least one of the changes in C++11 that will cause some old code to stop compiling: the introduction of explicit operator bool() in the standard library, replacing old instances of operator void*(). Granted, the code that this will break is probably code that should not have been valid in the first place, but it's still a breaking change nonetheless: programs that used to be valid no longer are.
Are there any other breaking changes?
The FDIS has a section for incompatibilities, at appendix C.2 "C++ and ISO C++ 2003".
Summary, paraphrasing the FDIS here, to make it (better) suitable as a SO answer. I added some examples of my own to illustrate the differences.
There are a few library-related incompatibilities where I don't exactly know the implications of, so I leave those for others to elaborate on.
Core language
#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 .
New keywords: alignas, alignof, char16_t, char32_t, constexpr, decltype, noexcept, nullptr, static_assert, and thread_local
Certain integer literals larger than can be represented by long could change from an unsigned integer type to signed long long.
Valid C++ 2003 code that uses integer division rounds the result toward 0 or toward negative infinity, whereas C++0x always rounds the result toward 0.
(admittedly not really a compatibility problem for most people).
Valid C++ 2003 code that uses the keyword auto as a storage class specifier may be invalid in C++0x.
Narrowing conversions cause incompatibilities with C++03. For example, the following code is valid in C++ 2003 but invalid in this International Standard because double to int is a narrowing conversion:
int x[] = { 2.0 };
Implicitly-declared special member functions are defined as deleted when the implicit definition would have been ill-formed.
A valid C++ 2003 program that uses one of these special member functions in a context where the definition is not required (e.g., in an expresion that is not potentially evaluated) becomes ill-formed.
Example by me:
struct A { private: A(); };
struct B : A { };
int main() { sizeof B(); /* valid in C++03, invalid in C++0x */ }
Such sizeof tricks have been used by some SFINAE, and needs to be changed now :)
User-declared destructors have an implicit exception specification.
Example by me:
struct A {
~A() { throw "foo"; }
};
int main() { try { A a; } catch(...) { } }
This code calls terminate in C++0x, but does not in C++03. Because the implicit exception specification of A::~A in C++0x is noexcept(true).
A valid C++ 2003 declaration containing export is ill-formed in C++0x.
A valid C++ 2003 expression containing > followed immediately by another > may now be treated as closing two templates.
In C++03, >> would always be the shift-operator token.
Allow dependent calls of functions with internal linkage.
Example by me:
static void f(int) { }
void f(long) { }
template<typename T>
void g(T t) { f(t); }
int main() { g(0); }
In C++03, this calls f(long), but in C++0x, this calls f(int). It should be noted that in both C++03 and C++0x, the following calls f(B) (the instantiation context still only considers extern linkage declarations).
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); }
The better matching f(A) is not taken, because it does not have external linkage.
Library changes
Valid C++ 2003 code that uses any identifiers added to the C++ standard
library of C++0x may fail to compile or produce different results in This International Standard.
Valid C++ 2003 code that #includes headers with names of new C++0x standard library headers may be invalid in this International Standard.
Valid C++ 2003 code that has been compiled expecting swap to be in <algorithm> may have to instead include <utility>
The global namespace posix is now reserved for standardization.
Valid C++ 2003 code that defines override, final, carries_dependency, or noreturn as macros is invalid in C++0x.
The meaning of the auto keyword changed.
Breaking change?
Well, for one thing, if you used decltype, constexpr, nullptr, etc. as identifiers then you may be in trouble...
Some core incompatibilities that are not covered by the incompatibilities section:
C++0x treats the injected class name as a template, if the name is passed as an argument to a template template parameter, and as a type if it is passed to a template type parameter.
Valid C++03 code may behave differently if it relies on the injected class name to be always a type in these scenarios. Example code taken from my 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();
}
In C++03, the code calls the second g both times.
C++0x makes some names that were dependent in C++03 to be now non-dependent. And requires name lookup for non-dependent qualified names that refer to members of the current class template to be repeated at instantiation, and requires verification that these names lookup the same way as done at the template definition context.
Valid C++03 code that depends on the dominance rule may now not compile anymore because of this change.
Example:
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(); }
This valid C++03 code that calls A<int>::f is not valid in C++0x, because name lookup when instantiating will find A<int>::f as opposed to B::f, causing a conflict with the at-definition lookup.
At this point, it is not clear whether that is a defect in the FDIS. The committee is aware of this and will evaluate the situation.
A using declaration where the last part is the same as the identifier in the last part of the qualifier in the qualified name denoting a base class, that using declaration now names the constructor, instead of members with that name.
Example:
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; }
The above example code is well-formed in C++03, but ill-formed in C++0x, as A::B is still inaccessible in main.
Stream extraction failure is treated differently.
Example
#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
}
Change proposal
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2011/n3246.html#23
Standard reference
[C++03: 22.2.2.1.2/11]: The result of stage 2 processing can be one of
A sequence of chars has been accumulated in stage 2 that is converted (according to the rules of scanf) to a value of the type of val. This value is stored in val and ios_base::goodbit is stored in err.
The sequence of chars accumulated in stage 2 would have caused scanf to report an input failure. ios_base::failbit is assigned to err. [ed: Nothing is stored in val.]
[C++11: 22.4.2.1.2/3]: [..] The numeric value to be stored can be one of:
zero, if the conversion function fails to convert the entire field. ios_base::failbit is assigned to err.
the most positive representable value, if the field represents a value too large positive to be represented in val. ios_base::failbit is assigned to err.
the most negative representable value or zero for an unsigned integer type, if the field represents a value too large negative to be represented in val. ios_base::failbit is assigned to err.
the converted value, otherwise.
The resultant numeric value is stored in val.
Implementations
GCC 4.8 correctly outputs for C++11:
Assertion `x == -1' failed
GCC 4.5-4.8 all output for C++03 the following, which would appear to be a bug:
Assertion `x == -1' failed
Visual C++ 2008 Express correctly outputs for C++03:
Assertion failed: x == 0
Visual C++ 2012 Express incorrectly outputs for C++11, which would appear to be a status-of-implementation issue:
Assertion failed: x == 0
How is the introduction of explicit conversion operators a breaking change? The old version will still just be as "valid" as before.
Yes, the change from operator void*() const to explicit operator bool() const will be a breaking change, but only if it is used in a way that is wrong in and out of itself. Conforming code won't be broken.
Now, another breaking change is the banning of narrowing conversions during aggregate initialization:
int a[] = { 1.0 }; // error
Edit: Just rememberer, std::identity<T> will be removed in C++0x (see the note). It's a convenience struct to make types dependent. Since the struct really doesn't do much, this should fix it:
template<class T>
struct identity{
typedef T type;
};
There are numerous changes to the containers library that allow more efficient code but silently break backwards compatibility for a few corner cases.
Consider, for example, std::vector, default construction, C++0x, and breaking changes.
There's been a lot of discussion of implicit move breaking backward compatibility
(an older page with relevant discussion)
If you read down into the comments, implicit move return is also a breaking change.
struct x {
x(int) {}
};
void f(auto x = 3) { }
int main() {
f();
}
C++03: valid.
C++0x: error: parameter declared 'auto'