Thursday, August 14, 2014

Project – Enable C++11 Compiling

By default, GCC C++ compiles for the corrected C++98 standard (C++03) with GNU extensions (there is no option for compiling for the uncorrected original C++98 standard).  There are two options for compiling C++11, one for the standard and one with GNU extensions.  The option for the standard C++11 will be used and was added to the CMake build file.

Though not necessary, I decided that it was a reasonable idea to validate that C++11 compiling was enabled and that C++11 was supported while generating the make file.  This meant adding a try_compile command to the CMake build file for a simple C++11 program.  If compiling of the simple program fails, an error is reported and CMake aborts.

The initial simple C++11 program tests two C++11 features.  As more C++11 features are used in the project, this simple program will be expanded to test those features also.  The two initial features tested are the new universal initializer syntax and the new null pointer.  Click Continue... for details of these two features.

I discovered something about CMake syntax, namely else and endif statements no longer require repeating the expression in the if statement (as of CMake 2.6.0).  The expression may now be left empty.  Repeating the expression can sometimes be misleading, for example:
if (NOT ${SOMETHING})
   
... <not something processing here> ...
else  (NOT ${SOMETHING})
   
... <something procession here> ...
endif (NOT ${SOMETHING})
Which makes it seem like the else part is for handling the "not something" condition.  Leaving the expression blank, as in else() and endif(), is much less confusing.  The rest of the if-else-endif statements in the CMake file will be updated to this style at some point.  (This syntax was already used for handling issues with Windows.)

There was also a statement in the CMake build file that obtained the GCC version for checking, but statements that were checking the version have been since removed, so this statement was also removed.  Work is now taking place on a new cpp11 branch.

[branch cpp11 commit 18ed38e9af]


Universal Initializer Syntax

The new universal initializer syntax uses values in braces for initializer values.  This is like the standard C initializer for initializing an array:
int a[4] = {1, 2, 3, 4};
This type of initializer can now be applied to all variables types:
int i = {1};
double d = {2.0};
Also, the equal (=) operator is optional (and it apparently is preferred to leave it out).  These initializers can also be used on used to initialize members on a constructor where parentheses were used before:
Class::Class(int i, double d) : m_i {i}, m_d {d} {}
This syntax can also be used with the new operator and with constant values:
int *pi = new int{1};
func(int{25});
An advantage of this syntax is that it prevents narrowing (converting a higher value to a lower value), for example:
double d = 123.5;
int i1 = d;          ← this line is accepted (may be an error)
int i2 {d};          ← this line produces a narrowing error
This could catch possible programming errors.  There are probably a few other places where universal initializers can be used.  The new try compile test program tests just a few cases.

Null Pointer

It was the tradition in C programs to use the definition NULL to represent an unset pointer.  This definition is obtained by including stdio.h (and probably a few other standard headers).  This definition is defined as zero (when include by a C++ program) or to a void pointer with a value of zero (C program).  It was the tradition of C++ programs to just use the zero constant to represent an unset pointer.  An actual pointer will never have a zero value.

The problem is that the NULL definition and the zero constant have an integer type (C++), allowing the following statements to be accepted:
int *p1 = 0;         ← okay, a null pointer
int *p2 = NULL;      ← okay, a null pointer
int i = NULL;        ← accepted, but this may be an error
The new nullptr value that is part of C++11 is an actual unset pointer of any type, but it is not interchangeable as an integer value, therefore:
int *p1 {nullptr};   ← any pointer type can be set to nullptr
int i = nullptr;     ← error, nullptr is not an integer
The new try compile test program tests one case of this.

No comments:

Post a Comment

All comments and feedback welcomed, whether positive or negative.
(Anonymous comments are allowed, but comments with URL links or unrelated comments will be removed.)