Can C++ code be valid in both C++03 and C++11 but do different things?
c++, c++03, c++11, language-lawyer
Solution
The answer is a definite yes. On the plus side there is:
- Code that previously implicitly copied objects will now implicitly move them when possible.
On the negative side, several examples are listed in the appendix C of the standard. Even though there are many more negative ones than positive, each one of them is much less likely to occur.
String literals
#define u8 "abc"
const char* s = u8"def"; // Previously "abcdef", now "def"
and
#define _x "there"
"hello "_x // Previously "hello there", now a user defined string literal
Type conversions of 0
In C++11, only literals are integer null pointer constants:
void f(void *); // #1
void f(...); // #2
template<int N> void g() {
f(0*N); // Calls #2; used to call #1
}
Rounded results after integer division and modulo
In C++03 the compiler was allowed to either round towards 0 or towards negative infinity. In C++11 it is mandatory to round towards 0
int i = (-1) / 2; // Might have been -1 in C++03, is now ensured to be 0
Whitespaces between nested template closing braces >> vs > >
Inside a specialization or instantiation the `>>` might instead be interpreted as a right-shift in C++03. This is more likely to break existing code though: (from http://gustedt.wordpress.com/2013/12/15/a-disimprovement-observed-from-the-outside-right-angle-brackets/)
template< unsigned len > unsigned int fun(unsigned int x);
typedef unsigned int (*fun_t)(unsigned int);
template< fun_t f > unsigned int fon(unsigned int x);
void total(void) {
// fon<fun<9> >(1) >> 2 in both standards
unsigned int A = fon< fun< 9 > >(1) >>(2);
// fon<fun<4> >(2) in C++03
// Compile time error in C++11
unsigned int B = fon< fun< 9 >>(1) > >(2);
}
Operator `new` may now throw other exceptions than `std::bad_alloc`
struct foo { void *operator new(size_t x){ throw std::exception(); } }
try {
foo *f = new foo();
} catch (std::bad_alloc &) {
// c++03 code
} catch (std::exception &) {
// c++11 code
}
User-declared destructors have an implicit exception specification example from What breaking changes are introduced in C++11?
struct A {
~A() { throw "foo"; } // Calls std::terminate in C++11
};
//...
try {
A a;
} catch(...) {
// C++03 will catch the exception
}
`size()` of containers is now required to run in O(1)
std::list<double> list;
// ...
size_t s = list.size(); // Might be an O(n) operation in C++03
`std::ios_base::failure` does not derive directly from `std::exception` anymore
While the direct base-class is new, `std::runtime_error` is not. Thus:
try {
std::cin >> variable; // exceptions enabled, and error here
} catch(std::runtime_error &) {
std::cerr << "C++11\n";
} catch(std::ios_base::failure &) {
std::cerr << "Pre-C++11\n";
}
Problem
Is it possible for C++ code to conform to both the C++03 standard and the C++11 standard, but do different things depending on under which standard it is being compiled?
Related problems
- What differences, if any, between C++03 and C++11 can be detected at run-time?
- Are multiple mutations within initializer lists undefined behavior?
- Is left-shifting (<<) a negative integer undefined behavior in C++11?
- What breaking changes are introduced in C++11?
- Why std::sort doesn't accept Compare classes declared within a function
- Are multiple mutations of the same variable within initializer lists undefined behavior pre C++11