Monday, February 27, 2012

C++'11: auto keyword

auto keyword
Forget everything you know about the auto keyword. Section 7.1.1 of the standard forgot it like this:

The auto and register specifiers shall be applied only to names of objects declared in a block (6.3) or to function parameters (8.4). They specify It specifies that the named object has automatic storage duration (3.7.2). An object declared without a storage-class-specifier at block scope or declared as a function parameter has automatic storage duration by default. [Note: hence, the auto specifier is almost always redundant and not often used; one use of auto is to distinguish a declaration-statement from an expression-statement (6.8) explicitly.—end note]

Standards committee members searched through millions of lines of code and found only a few rare examples of its use, so they hijacked it for something everyone will use. It is now an auto initializer for variables. Borrowing heavily from the change submission [n1984] we will look at a few code examples:

auto x = 3.14; // x has type double

int foo();
auto x1 = foo(); //x1:int
const auto& x2 = foo(); //x2: const int&
auto& x3 = foo(); //x3: int&: error, cannot bind a reference to a temporary

float& bar();
auto y1 = bar(); //y1: float. Value semantics is the default (notice y1 is not of type float&)
const auto& y2 = bar(); //y2: const float&
auto& y3 = bar(); //y3: float&

A* fii();
auto* z1 = fii(); //z1: A*
auto z2 = fii(); //z2: A*
auto* z3 = bar(); //error, bar does not return a pointer type

The way it deduces the type to use is the same as how templates do it. i.e. in the code snipit:
const auto &i = expr;
The type of i is the deduced type of teh parameter u of teh call f(expr) of the following invented function template:
template void f(const U& u);
(see section 7.1.5.4 of the standard for the note on this)

You are even allowed to have multiple declarations on one line, but they must all be of the same type, just as if you specified the type. For example:
int i;
auto a = 1, *b = &1; //int and int*


The interesting thing that is missing is the ability to use auto with arrays. This is because an array decays into a pointer to the first element, which makes it difficult to specify the behavior in a way that is both consistent with the language and simple to understand. See section 8.3.4 paragraph 1, where it is explicitly banned.

Sunday, February 19, 2012

C++'11: C99 compatibility

When I was first learning how to program, I stumbled across the now defunct website programing.com [sic] where someone posed the question "What is the difference between C and C++?" The first response to the question said that "The difference is in C you say printf, but in C++ you say cout." I thought it was so funny that I showed all my software friends.

C compatibility has been one of the greatest advantages of the C++ language. Without it the language would have been (as Bjarne put it in D&E) stillborn. It has also been one of the biggest sources of problems in the language. I frequently deal with these kind of issues when integrating COTS C code with C++. The ISO C standard was updated for the first time in 11 years in 1999, a year after C++'98 was released. It was updated again in 2011 around the same time as C++'11. The two committees coordinated many of their changes to continue their symbiosis.

For an interesting discussion on incompatibility between the languages see appendix C of the standards document. The appendix is informative and not part of the actual C++ language definition but it is still worth your time if you work much with C and C++ together.

long long
long long was officially added to define an integer that is at least 64 bits long. Along with that comes unsigned long long and the literal constants LL/ll and ULL/ull. printf also has the ll length specifier. long long has been the de facto standard for awhile so it will probably be a surprise to some that it was not officially in the language before now. In was actually proposed back in 1995 but at the time was rejected because C had not yet officially adopted it yet. Here is a little code example:
 long long myNumber = -1234567LL;
unsigned long long uMyNumber = 8446744073709551616ULL; //That is a large number
printf("%lld and %llu\n", myNumber, uMyNumber);
See for [n1811] for more information.

Extended Integer Types
The C++ language did not adopt actual Extended Integer types. i.e. 128-bit integers or larger. They did however define a way for them to behave is an implementation decided to provide them. In a nutshell, they will behave basically how you would expect them to when it comes to things like implicit conversions. For the most part a normal developer should not need to worry about it or even know about this language extension because any use of it would not be portable. It should be avoided unless there is a good reason to use it. The C language, as well as the ECMA C++ Binding for CLI standard (that is the European Computer Manufactures Association) have already adopted it, so for the sake of not creating a C++ dialect the committee picked it up too. See [1988] for more information.

Other Stuff...
A bunch of other misc. things were carried over. Maybe the biggest thing was updates to the C libraries, a quick scan of [n1568] will show you more detail than you probably care to know about some of the compatibility library updates. I am choosing to gloss over changes like the updates to the preprocessor and C style strings in hopes that they will be touched on in another post. One important difference to point out though, is C++ did not adopt the Variable Length Arrays. Sorry, I guess you will just have to continue using new() for a variable length - or better yet use the new array class in the Standard Template Library.


C++'11: __cplusplus macro updated

The macro __cplusplus in now defined to have a value of 201103L. This is outlined in section 16.8 [cpp.predefined] of the standard. This value is expected to be updated in each release. As the standards document says:
"It is intended that future versions of this standard will replace the value of this macro with a greater value. Non-conforming compilers should use a value with at most five decimal digits."
If you use GCC though, be aware that they just recently fixed their bug that caused the value to be always set to 1 instead of the previous standards value 199711L. See their bug report here for more details and some interesting insight into why something as simple as #define __cplusplus 199711L is not always so simple.