C++11
C++0x is the planned new standard for the C++ programming language. It is intended to replace the existing C++ standard, ISO/IEC 14882, which was published in 1998 and updated in 2003. These predecessors are informally known as C++98 and C++03. The new standard will include several additions to the core language and will extend the C++ standard library, incorporating most of the C++ Technical Report 1 libraries — most likely with the exception of the library of mathematical special functions. Since the standard is not yet finalized, this article may not reflect the most recent state of C++0x. Up-to-date state of the next C++ standard is published on the ISO C++ committee website. The most recent report, N2800, was published in October 2008.
The ISO/IEC JTC1/SC22/WG21 C++ Standards Committee aims to introduce the new standard in 2009 (hence the standard that is today called C++0x will become C++09) which means that the document was intended to be ready for ratification of the member states of ISO in 2008, so that it would be published in 2009. To be able to finish on schedule, the Committee decided to focus its efforts on the solutions introduced up until 2006 and ignore newer proposals [1]. However, it's now clear that the Standard will probably be ready for ratification in late 2009 and be published in 2010.
Programming languages such as C++ use an evolutionary process to develop their definition. This process inevitably raises compatibility issues with existing code, which has happened occasionally during the C++ development process. However, according to the announcement made by Bjarne Stroustrup (inventor of the C++ language and member of the committee), the new standard will be almost 100% compatible with the current standard [2].
Candidate changes for the impending standard update
The modifications for C++ will involve both the core language and the standard library.
In the development of every utility of the new standard, the committee has applied some directives:
- Maintain stability and compatibility with C++98 and possibly with C;
- Prefer introduction of new features through the standard library, rather than extending the core language;
- Prefer changes that can evolve the programming technique;
- Improve C++ to facilitate systems and library design, rather than to introduce new features only useful to specific applications;
- Increase type safety by providing safer alternatives to current, unsafe techniques;
- Increase performance and the ability to work directly with hardware;
- Provide proper solutions for real world problems;
- Implement “zero-overhead” principle (additional support required by some utilities must be used only if the utility is used);
- Make C++ easy to teach and to learn without removing any utility needed by expert programmers.
Attention to beginners is important, because they will always comprise the majority of computer programmers, and because many beginners do not intend to extend their knowledge of C++, limiting themselves to operate in the fields in which they are specialized [1]. Additionally, considering the vastness of C++ and its usage (including areas of application and programming styles), even the most experienced programmers can become beginners in a new programming paradigm.
Extensions to the C++ core language
The main focus of the C++ committee is the development of the language core. The presentation date of C++0x depends on the progress of this part of the standard.
Areas of the core language that will be significantly improved include multithreading support, generic programming support, uniform initialization, and performance enhancements.
For the purposes of this page, core language features and changes are grouped into 4 general sections: runtime performance enhancements, build time performance enhancements, usability enhancements, or new functionality. Some features could fall into multiple groups, but they will only be mentioned in the one that feature primarily represents.
Core language runtime performance enhancements
These language features primarily exist to provide some kind of performance benefit. This can be memory or speed.
Rvalue reference and move semantics
In standard C++, temporaries (termed "R-values", as they lie on the right side of an assignment) can be passed to functions, but they can only be accepted as const & types. As such, it is impossible for a function to distinguish between an actual R-value and a regular object that is passed as const &. Furthermore, since the type is const &, it is not possible to actually change the object.
C++0x will add a new reference type called an R-value reference. It is defined as typename &&. These can be accepted as non-const values, which allows an object to modify them. This modification allows for certain objects to create move semantics.
For example, a std::vector is, internally, a wrapper around a C-style array with a size. If a vector temporary is created or returned from a function, it can only be stored by creating a new vector and having it copy all of the R-value's data into it. Then the temporary is destroyed, deleting its data.
With R-value references, a "move constructor" of std::vector that takes an R-value reference to a vector can simply copy the pointer to the internal C-style array out of the R-value into the new vector, then leave the R-value in an empty state. There is no array copying, and the destruction of the empty temporary does not destroy the memory. The function returning a vector temporary need only return a std::vector<>&&. If vector has no move constructor, then the copy constructor will be invoked with a const std::vector<> & as normal. If it does have a move constructor, then the move constructor can be invoked, and significant memory allocation can be avoided.
For safety reasons a named variable will never be considered to be an R-value even if it's declared as such; in order to get an R-value the library function std::move() should be used.
bool is_r_value(int &&) { return true; }
bool is_r_value(const int &) { return false; }
void test(int && i)
{
is_r_value(i); // false
is_r_value(std::move(i)); // true
}
Due to the nature of the wording of R-value references, and to some modification to the wording for L-value references (regular references), R-value references allow developers to provide perfect function forwarding. When combined with variadic templates, this ability allows for function templates that can perfectly forward arguments to another function that takes those particular arguments. This is most useful for forwarding constructor parameters, to create factory functions that will automatically call the correct constructor for those particular arguments.
Generalized constant expressions
C++ has always had the concept of constant expressions. These are expressions such as 3+4 that will always yield the same results and that have no side effects. Constant expressions are optimization opportunities for compilers, and compilers frequently execute them at compile time and store the results in the program. Also, there are a number of places where the C++ specification requires the use of constant expressions. Defining an array requires a constant expression, and enumerator values must be constant expressions.
However, constant expressions have always ended whenever a function call or object constructor was encountered. So something as simple as this is illegal:
int GetFive() {return 5;}
int some_value[GetFive() + 5]; //create an array of 10 integers. illegal C++
This is not legal C++, because GetFive() + 5 is not a constant expression. The compiler has no way of knowing if GetFive actually is constant at runtime. In theory, this function could affect a global variable, call other non-runtime constant functions, etc.
C++0x will introduce the keyword constexpr, which allows the user to guarantee that a function or object constructor is a compile-time constant. The above example can be rewritten as follows:
constexpr int GetFive() {return 5;}
int some_value[GetFive() + 5]; //create an array of 10 integers. legal C++0x
This allows the compiler to understand, and verify, that GetFive is a compile-time constant.
The use of constexpr on a function imposes very strict limitations on what that function can do. First, the function must have a non-void type. Second, the function contents must be of the form, "return expr". Third, expr must be a constant expression, after argument substitution. This constant expression may only call other functions defined as constexpr, or it may use other constant expression data variables. Lastly, a function with this label cannot be called until it is defined in this translation unit.
Variables can also be defined as constant expression values:
constexpr double accelerationOfGravity = 9.8;
constexpr double moonGravity = accelerationOfGravity / 6;
Constant expression data variables are implicitly const. They can only store the results of constant expressions or constant expression constructors.
In order to construct constant expression data values from user-defined types, constructors can also be declared with constexpr. A constant expression constructor must be defined before its use in the translation unit, as with constant expression functions. It must have an empty function body. It must initialize its members with constant expressions. And the destructors for such types should be trivial.
Copying constexpr constructed types should also be defined as a constexpr, in order to allow them to be returned by value from a constexpr function. Any member function of a class, such as copy constructors, operator overloads, etc, can be declared as constexpr, so long as they fit the definition for function constant expressions. This allows the compiler to copy classes at compile time, perform operations on them, etc.
A constant expression function or constructor can be called with non-constexpr parameters. Just as a constexpr integer literal can be assigned to a non-constexpr variable, so too can a constexpr function be called with non-constexpr parameters, and the results stored in non-constexpr variables. The keyword only allows for the possibility of compile-time constancy when all members of an expression are constexpr.
Modification to the definition of plain old data
In standard C++, a struct must follow a number of rules in order for it to be considered a plain old data (POD) type. There are good reasons for wanting a larger number of types to fit this definition. Types that fit this definition allow implementations to produce object layouts that are compatible with C. However, the list of rules in C++03 is overly strict.
C++0x will relax several rules with regard to the POD definition.
A class/struct is considered a POD if it is trivial, standard-layout, and if all of its non-static members are PODs.
A trivial class or struct is defined as one that:
- Has a trivial default constructor. This may use the default constructor syntax (SomeConstructor() = default;).
- Has a trivial copy constructor, which may use the default syntax.
- Has a trivial copy assignment operator, which may use the default syntax.
- Has a trivial destructor, which must not be virtual.
A standard-layout class or struct is defined as one that:
- Has only non-static data members that are of standard-layout type
- Has the same access control (public, private, protected) for all non-static members
- Has no virtual functions
- Has no virtual base classes
- Has only base classes that are of standard-layout type
- Has no base classes of the same type as the first defined non-static member
- Either has no base classes with non-static members, or has no non-static data members in the most derived class and at most one base class with non-static members. In essence, there may be only one class in this class's hierarchy that has non-static members.
Core language build time performance enhancements
Extern template
In standard C++, the compiler must instantiate a template whenever a fully specified template is encountered in a translation unit. This can dramatically increase compile time, particularly if the template is instantiated in many translation units using the same parameters. There is no way to tell C++ not to provoke an instantiation of a template.
C++0x will introduce the idea of external templates. C++ already has syntax for forcing the compiler to instantiate at a particular location:
template class std::vector<MyClass>;
What C++ lacks is the ability to prevent the compiler from instantiating a template in a translation unit. C++0x will simply extend this syntax to:
extern template class std::vector<MyClass>;
This tells the compiler not to instantiate the template in this translation unit.
Core language usability enhancements
These features exist for the primary purpose of making the language easier to use. These can improve type safety, minimize code repetition, make it more difficult to erroneously use code, or something similar.
Initializer lists
Standard C++ borrows the initializer list concept from C. The idea is that a struct or array can be created giving a list of arguments in the order of the members' definitions in the struct. These initializer lists are recursive, so an array of structs or struct containing other structs can use them. This is very useful for static lists or just for initializing a struct to a particular value. C++ has constructors, which can replicate the initialization of an object. But that alone does not replace all of the utility of this feature. Standard C++ allows this on structs and classes, except that these objects must conform to the Plain Old Data (POD) definition; non-POD classes cannot use initializer lists, nor can useful C++-style containers like std::vector.
C++0x will bind the concept of initializer lists to a type, called std::initializer_list. This allows constructors and other functions to take initializer lists as parameters. For example:
class SequenceClass
{
public:
SequenceClass(std::initializer_list<int> list);
};
This will allow SequenceClass to be constructed from a sequence of integers, as such:
SequenceClass someVar = {1, 4, 5, 6};
This constructor is a special kind of constructor, called an initializer list constructor. Classes with such a constructor are treated specially during uniform initialization.
The class std::initializer_list<> is a first-class C++0x standard library type. However, they can only be initially constructed statically by the C++0x compiler through the use of the {} syntax. The list can be copied once constructed, though this is only a copy-by-reference. An initializer list is constant; its members cannot be changed once the initializer list is created, nor can the data in those members be changed.
Because initializer_list is a real type, it can be used in other places besides class constructors. Regular functions can take typed initializer lists as arguments. For example:
void FunctionName(std::initializer_list<float> list);
FunctionName({1.0f, -3.45f, -0.4f});
Standard containers can also be initialized this way:
vector<string> v = { "xyzzy", "plugh", "abracadabra" };
Uniform initialization
Standard C++ has a number of problems with initializing types. There are several ways to initialize types, and they do not all produce the same results when interchanged. The traditional constructor syntax, for example, can look like a function declaration, and steps have to be taken to ensure that the compiler will not mistake it for such. Only aggregates and POD types can be initialized with aggregate initializers (using SomeType var = {/*stuff*/};
).
C++0x will provide a syntax that allows for fully uniform type initialization that will work on any object. It expands on the initializer list syntax:
struct BasicStruct
{
int x;
float y;
};
struct AltStruct
{
AltStruct(int _x, float _y) : x(_x), y(_y) {}
private:
int x;
float y;
};
BasicStruct var1{5, 3.2f};
AltStruct var2{2, 4.3f};
The initialization of var1 functions exactly as though it were a C-style initializer list. Each public variable will be initialized with each value of the initializer list. Implicit type conversion will be used where necessary, but if there is no type conversion available, compilation will fail.
The initialization of var2 simply calls the constructor.
The uniform initialization construct can remove the need for specifying certain types:
struct IdString
{
std::string name;
int identifier;
};
IdString var3{"SomeName", 4};
This syntax will automatically initialize the std::string with the const char * parameter. One is also able to do the following:
IdString GetString()
{
return {"SomeName", 4}; //Note the lack of explicit type.
}
Uniform initialization will not replace constructor syntax. There will still be times when constructor syntax will be required. If a class has an initializer list constructor (TypeName(initializer_list<SomeType>);), then it takes priority over other forms of construction, if the initializer list conforms to the sequence constructor's type. The C++0x version of std::vector will have an initializer list constructor for its template type. This means that:
std::vector<int> theVec{4};
This will call the initializer list constructor, not the constructor of std::vector that takes a single size parameter and creates the vector with that size. To access this constructor, the user will need to use the standard constructor syntax directly.
Type inference
In standard C++ (and C), the type of a variable must be explicitly specified in order to use it. However, with the advent of template types and template metaprogramming techniques, the type of something, particularly the well-defined return value of a function, may not be easily expressed. As such, storing intermediates in variables is difficult, possibly requiring knowledge of the internals of a particular metaprogramming library.
C++0x allows this to be mitigated in two ways. First, the definition of a variable with an explicit initialization can use the auto keyword. This creates a variable of the specific type of the initializer:
auto someStrangeCallableType = boost::bind(&SomeFunction, _2, _1, someObject);
auto otherVariable = 5;
The type of someStrangeCallableType is simply whatever the particular template function override of boost::bind
returns for those particular arguments. This type is easily determined procedurally by the compiler as part of its semantic analysis duties, but is not easy for the user to determine upon inspection.
The type of otherVariable is also well-defined, but it is easier for the user to determine. It is an int, which is the same type as the integer literal.
Additionally, the keyword decltype can be used to determine the type of an expression at compile-time. For example:
int someInt;
decltype(someInt) otherIntegerVariable = 5;
This is more useful in conjunction with auto, since the type of an auto variable is known only to the compiler. However, decltype can also be very useful for expressions in code that makes heavy use of operator overloading and specialized types.
auto
is also useful for reducing the verbosity of the code. For instance, instead of writing
for (vector<int>::const_iterator itr = myvec.begin(); itr != myvec.end(); ++itr)
the programmer can use the shorter
for (auto itr = myvec.begin(); itr != myvec.end(); ++itr)
This difference grows as the programmer begins to nest containers, though in such cases typedef
s are a good way to decrease the amount of code.
The type denoted by decltype is often different from the type deduced by auto.
#include <vector>
int main()
{
const std::vector<int> v(1);
auto a = v[0]; // a has type int
decltype(v[0]) b; // b has type const int&, the return type of
// std::vector<int>::operator[](size_type) const
auto c = 0; // c has type int
auto d = c; // d has type int
decltype(c) e; // e has type int, the type of the entity named by c
decltype((c)) f; // f has type int&, because (c) is an lvalue
decltype(0) g; // g has type int, because 0 is an rvalue
}
Range-based for-loop
The Boost C++ library defines a number of "Range" concepts. Ranges represent a controlled list, much like a container, between two points in that list. Ordered containers are a superset of the range concept, and two iterators in an ordered container can define a range as well. These concepts, and algorithms that operate on them, will be incorporated into C++0x's standard library. However, the utility of range concepts is such that C++0x will provide a language feature built around them.
The statement for will allow for easy iteration over a range concept:
int my_array[5] = {1, 2, 3, 4, 5};
for(int &x : my_array)
{
x *= 2;
}
The first section of the new for loop defines the variable that will be used to iterate over the range. The variable, as with variables declared in the regular for-loop, only has scope for the duration of the loop. The second section, after the ":", represents the range concept being iterated over. In this case, there is a concept map that allows C-style arrays to be converted into range concepts. This could have been a std::vector, or any object that conforms to a range concept.
Lambda functions and expressions
In standard C++, particularly when used with C++ standard library algorithm functions such as sort and find, the user will often wish to define predicate functions near the place where they make the algorithm function call. The language has only one mechanism for this: the ability to define a class inside of a function. This is often cumbersome and verbose, as well as interrupting the flow of the code. Additionally, standard C++'s rules for classes defined in functions do not permit them to be used in templates, so using them is simply not possible.
The obvious solution would be to allow for the definition of lambda expressions and lambda functions. C++0x will allow for the definition of lambda functions.
A lambda function is defined as follows:
[](int x, int y) { return x + y; }
The return type of this unnamed function is decltype(x+y). The return type can only be omitted if the lambda function is of the form "return expression". This limits the lambda function to one statement.
The return type can be explicitly specified as follows, for a more complicated example:
[](int x, int y) -> int { int z = x + y; return z + x; }
In this example, a temporary variable, z, is created to store an intermediate. As with normal functions, the value of this intermediate is not held between invocations.
The return type can be omitted entirely if the lambda function does not return a value (i.e. if the return type is void).
References to variables defined in the same scope as the lambda function can be used as well. The set of variables of this sort is commonly called a closure. Closures are defined and used as follows:
std::vector<int> someList;
int total = 0;
std::for_each(someList.begin(), someList.end(), [&total](int x) {
total += x
});
std::cout << total;
This would display the total of all elements in the list. The variable total is stored as a part of the lambda function's closure. Since it is a reference to the stack variable total, it can change its value.
Closure variables for local variables can also be defined without the reference symbol &, which indicates that the lambda function will copy the value. This forces the user to declare their intent to reference local variables or copy them. If a closure object containing references to local variables is invoked after the innermost block scope of its creation, the behaviour is undefined.
For lambda functions that are guaranteed to run in the scope of its definition, it is possible to use all available stack variables without having to explicitly reference them:
std::vector<int> someList;
int total = 0;
std::for_each(someList.begin(), someList.end(), [&](int x) {
total += x
});
The specific internal implementation can vary, but the expectation is that the lambda function will store the actual stack pointer of the function it is created in, rather than individual references to stack variables.
If [=] is used instead of [&], all referenced variables will be copied, allowing the lambda function to be used after the end of the lifetime of the original variables.
The defaults can also be combined with lists. For example, if the user wants to capture most variables by reference, but have one by value, then the user can do the following:
int total = 0;
int value = 5;
[&, value](int x) { total += (x * value) };
This will cause total to be stored as a reference, but value will be stored as a copy.
If a lambda function is defined by a member function of a class, it is assumed to be a friend of that class. Such lambda functions can use a reference to an object of the class type and access its internal members:
[](SomeType *typePtr) { typePtr->SomePrivateMemberFunction() };
This will only work if the scope of this lambda function's creation is in a member function of SomeType.
The handling of the this pointer, referencing the object that the current member function is operating on, is special. It must be explicitly designated in the lambda function:
[this]() { this->SomePrivateMemberFunction() };
Using the [&] or [=] form of lambda functions will automatically make this available.
Lambda functions are function objects of a implementation-dependent type; this type's name is only available to the compiler. If the user wishes to take a lambda function as a parameter, the type must be a template type, or it must create a std::function to capture the lambda value. The use of the auto keyword can locally store the lambda function:
auto myLambdaFunc = [this]() { this->SomePrivateMemberFunction() };
However, if the lambda function captures all of its closure variables by reference, or if it has no closure variables, then its type shall be publicly derived from std::reference_closure<R(P)>, where R(P) is the function signature with return type. This is expected to be a more efficient representation for lambda functions than capturing them in a std::function:
std::reference_closure<void()> myLambdaFunc = [this]() { this->SomePrivateMemberFunction() };
myLambdaFunc();
Alternate function syntax
Standard C function declaration syntax was perfectly adequate for the feature set of the C language. As C++ evolved from C, it kept the basic syntax and extended it where necessary. However, as C++ became more complicated, it exposed a number of limitations, particularly with regard to template function declarations. The following, for example, is not allowable in C++03:
template< typename LHS, typename RHS>
Ret AddingFunc(const LHS &lhs, const RHS &rhs) {return lhs + rhs;} //Ret must be the type of lhs+rhs
The type Ret is whatever the addition of types LHS and RHS will produce. Even with the aforementioned C++0x functionality of decltype, this is not possible:
template< typename LHS, typename RHS>
decltype(lhs+rhs) AddingFunc(const LHS &lhs, const RHS &rhs) {return lhs + rhs;} //Not legal C++0x
This is not legal C++ because lhs and rhs have not yet been defined; they will not be valid identifiers until after the parser has parsed the rest of the function prototype.
To work around this, C++0x will introduce a new function definition and declaration syntax:
template< typename LHS, typename RHS>
auto AddingFunc(const LHS &lhs, const RHS &rhs) -> decltype(lhs+rhs) {return lhs + rhs;}
This syntax can be used for more mundane function declarations and definitions:
struct SomeStruct
{
auto FuncName(int x, int y) -> int;
};
auto SomeStruct::FuncName(int x, int y) -> int
{
return x + y;
}
Concepts
In C++, template classes and functions necessarily impose restrictions on the types that they take. For instance, the STL containers require that the contained types be assignable. Unlike the dynamic polymorphism that class inheritance hierarchies exhibit, where a function that accepts an object of type Foo&
can be passed any subtype of Foo
, any class can be supplied as a template parameter so long as it supports all of the operations that the template uses. In the case of the function the requirement an argument must meet is clear (being a subtype of Foo
), but in the case of a template the interface an object must meet is implicit in the implementation of that template. Concepts provide a mechanism for codifying the interface that a template parameter must meet.
The primary motivation of the introduction of concepts is to improve the quality of compiler error messages. If a programmer attempts to use a type that does not provide the interface a template requires, the compiler will generate an error. However, such errors are often difficult to understand, especially for novices. There are two main reasons for this. First, error messages are often displayed with template parameters spelled out in full; this leads to extremely large error messages. On some compilers, simple errors can generate several kilobytes of error messages. Second, they often do not immediately refer to the actual location of the error. For example, if the programmer tries to construct a vector
of objects that do not have a copy constructor, the first error almost always refers to the code within the vector
class itself that attempts to copy construct its contents; the programmer must be skilled enough to understand that the real error was that the type doesn't support everything the vector
class requires.
In an attempt to resolve this issue, C++0x adds the language feature of concepts. Similar to how OOP uses a base-class to define restrictions on what a type can do, a concept is a named construct that specifies what a type must provide. Unlike OOP, however, the concept definition itself is not always associated explicitly with the type being passed into the template, but with the template definition itself:
template<LessThanComparable T>
const T& min(const T &x, const T &y)
{
return y < x ? y : x;
}
Rather than using an arbitrary class
or typename
for the template type parameter, it uses LessThanComparable
, which is a concept that was previously defined. If a type passed into the min
template function does not satisfy the requirements of the LessThanComparable
concept, then a compile error will result, telling the user that the type used to instantiate the template does not fit the LessThanComparable
concept.
A more generalized form of the concept is as follows:
template<typename T> requires LessThanComparable<T>
const T& min(const T &x, const T &y)
{
return y < x ? y : x;
}
The keyword requires
begins a list of concept declarations. It can also be used for concepts that use multiple types. Additionally, it can be used as requires !LessThanComparable<T>
, if the user wishes to prevent the use of this particular template if the type matches the concept. This mechanism can be used in a way similar to template specialization. A general template would handle types with fewer features, explicitly disallowing the use of other, more feature-rich, concepts. And those concepts would have their own specializations that use those particular features to achieve greater performance or some other functionality.
Concepts are defined as follows:
auto concept LessThanComparable<typename T>
{
bool operator<(T, T);
}
The keyword auto
, in this instance, means that any type that supports the operations specified in the concept will be considered to support the concept. Without the use of the auto
keyword, then the type must use a concept map in order to declare itself as supporting the concept.
This concept says that any type that has an operator <
that takes two objects of that type and returns a bool
will be considered LessThanComparable
. The operator need not be a free-function; it could be a member function of the type T
.
Concepts can involve multiple objects as well. For example, concepts can express that a type is convertible from one type to another:
auto concept Convertible<typename T, typename U>
{
operator U(const T&);
}
In order to use this in a template, it must use a generalized form of concept usage:
template<typename U, typename T> requires Convertible<T, U>
U convert(const T& t)
{
return t;
}
Concepts may be composed. For example, given a concept named Regular
:
concept InputIterator<typename Iter, typename Value>
{
requires Regular<Iter>;
Value operator*(const Iter&);
Iter& operator++(Iter&);
Iter operator++(Iter&, int);
}
The first template parameter to the InputIterator
concept must conform to the Regular
concept.
Concepts can also be derived from one another, like inheritance. Like in class inheritance, types that meet the requirements of the derived concept also meet the requirements of the base concept. It is defined as per class derivation:
concept ForwardIterator<typename Iter, typename Value> : InputIterator<Iter, Value>
{
//Add other requirements here.
}
Typenames can also be associated with a concept. These impose the requirement that, in templates that use those concepts, these typenames are available:
concept InputIterator<typename Iter>
{
typename value_type;
typename reference;
typename pointer;
typename difference_type;
requires Regular<Iter>;
requires Convertible<reference, value_type>;
reference operator*(const Iter&); // dereference
Iter& operator++(Iter&); // pre-increment
Iter operator++(Iter&, int); // post-increment
// ...
}
Concept maps allow types to be explicitly bound to a concept. They also allow types to, where possible, adopt the syntax of a concept without changing the definition of the type. As an example:
concept_map InputIterator<char*>
{
typedef char value_type ;
typedef char& reference ;
typedef char* pointer ;
typedef std::ptrdiff_t difference_type ;
};
This map fills in the required typenames for the InputIterator
concept when applied to char*
types.
As an added degree of flexibility, concept maps themselves can be templated. The above example can be extended to all pointer types:
template<typename T> concept_map InputIterator<T*>
{
typedef T value_type ;
typedef T& reference ;
typedef T* pointer ;
typedef std::ptrdiff_t difference_type ;
};
Further, concept maps can act as mini-types, with function definitions and other constructs commonly associated with classes:
concept Stack<typename X>
{
typename value_type;
void push(X&, const value_type&);
void pop(X&);
value_type top(const X&);
bool empty(const X&);
};
template<typename T> concept_map Stack<std::vector<T> >
{
typedef T value_type;
void push(std::vector<T>& v, const T& x) { v.push_back(x); }
void pop(std::vector<T>& v) { v.pop_back(); }
T top(const std::vector<T>& v) { return v.back(); }
bool empty(const std::vector<T>& v) { return v.empty(); }
};
This concept map allows templates that take types that implement the concept Stack
to take a std::vector
, remapping the function calls directly to the std::vector
calls. Ultimately, this allows a pre-existing object to be converted, without touching the definition of the object, into an interface that a template function can utilize.
Finally, it should be noted that some requirements can be checked using static assertions. These can verify some requirements that templates need, but are really aimed at a different problem.
Object construction improvement
In standard C++, constructors are not allowed to call other constructors; each constructor must construct all of its class members itself or call a common member function. Constructors for base classes cannot be directly exposed to derived classes; each derived class must implement constructors even if a base class constructor would be appropriate. Non-constant data members of classes cannot be initialized at the site of the declaration of those members. They can only be initialized in a constructor.
C++0x will provide solutions to all of these problems.
C++0x will allow constructors to call other peer constructors (known as delegation). This will allow constructors to utilize another constructor's behavior with a minimum of added code. Other languages, such as Java and C#, provide this.
This syntax is as follows:
class SomeType
{
int number;
public:
SomeType(int newNumber) : number(newNumber) {}
SomeType() : SomeType(42) {}
};
Notice that, in this case, the same effect could have been achieved by making newNumber a defaulting parameter.
This comes with a caveat: C++03 considers an object to be constructed when its constructor finishes executing, but C++0x will consider an object constructed once any constructor finishes execution. Since multiple constructors will be allowed to execute, this will mean that each delegate constructor will be executing on a fully-constructed object of its own type. Derived class constructors will execute after all delegation in their base classes is complete.
For base-class constructors, C++0x will allow a class to specify that base class constructors will be inherited. This means that the C++0x compiler will generate code to perform the inheritance, the forwarding of the derived class to the base class. Note that this is an all-or-nothing feature; either all of that base class's constructors are forwarded or none of them are. Also, note that there are restrictions for multiple inheritance, such that class constructors cannot be inherited from two classes that use constructors with the same signature. Nor can a constructor in the derived class exist that matches a signature in the inherited base class.
The syntax will be as follows:
class BaseClass
{
public:
BaseClass(int iValue);
};
class DerivedClass : public BaseClass
{
public:
using BaseClass::BaseClass;
};
For member initialization, C++0x will allow the following syntax:
class SomeClass
{
public:
SomeClass() {}
explicit SomeClass(int iNewValue) : iValue(iNewValue) {}
private:
int iValue = 5;
};
Any constructor of the class will initialize iValue with 5, if the constructor does not override the initialization with its own. So the above empty constructor will initialize iValue as the class definition states, but the constructor that takes an int will initialize it to the given parameter.
It can also use constructor and uniform initialization, instead of the equality initialization shown above.
Null pointer constant
Since the dawn of C in 1972, the constant 0 has had the double role of constant integer and null pointer constant. The ambiguity inherent in the double meaning of 0 was dealt with in C by the use of the preprocessor macro NULL
, which usually expands to either ((void*)0)
or 0
. C++ didn't adopt the same behavior: only integral constant expressions that evaluates to zero are allowed as null pointer constants. This interacts poorly with function overloading:
void foo(char *);
void foo(int);
If NULL is defined as 0 (which is usually the case in C++), the statement foo(NULL);
will call foo(int)
, which is almost certainly not what the programmer intended, and not what a superficial reading of the code suggests.
C++0x aims to correct this by introducing a new keyword to serve as a distinguished null pointer constant : nullptr
. nullptr
is of type nullptr_t
, which is implicitly convertible and comparable to any pointer type or pointer-to-member type. It is not implicitly convertible or comparable to integer types.
For backwards compatibility reasons, integral constant expressions that evaluates to zero will remain valid null pointer constants.
char* pc = nullptr; // OK
int * pi = nullptr; // OK
int i = nullptr; // error
foo(nullptr); // calls foo(char *), not foo(int);
Strongly typed enumerations
In standard C++, enumerations are not type-safe. They are effectively integers, even when the enumeration types are distinct. This allows the comparison between two enum values of different enumeration types. The only safety that C++03 provides is that an integer or a value of one enum type does not convert implicitly to another enum type. Additionally, the underlying integral type, the size of the integer, cannot be explicitly specified; it is implementation defined. Lastly, enumeration values are scoped to the enclosing scope. As such, it is not possible for two separate enumerations to have matching member names.
C++0x will allow a special classification of enumeration that has none of these issues. This is expressed using the enum class declaration:
enum class Enumeration
{
Val1,
Val2,
Val3 = 100,
Val4 /* = 101 */,
};
This enumeration is type-safe. Enum class values are not implicitly converted to integers; as such, they cannot be compared to integers either (the expression Enumeration::Val4 == 101
gives a compiler error).
The underlying type of enum classes is explicitly specified. The default, as in the above case, is int, but it can be changed as follows:
enum class Enum2 : unsigned int {Val1, Val2};
The scoping of the enumeration is also defined as the enumeration name's scope. Using the enumerator names requires explicitly scoping. Val1 is undefined, but Enum2::Val1 is defined.
Additionally, C++0x will allow standard enumerations to provide explicit scoping as well as the definition of the underlying type:
enum Enum3 : unsigned long {Val1 = 1, Val2};
The enumerator names are defined in the enumeration's scope (Enum3::Val1), but for backwards compatibility, enumerator names are also placed in the enclosing scope.
Forward declaration of enums is also possible in C++0x. Previously, the reason enum types could not be forward declared is because the size of the enumeration depends on its contents. As long as the size of the enumeration is specified by the application, it can be forward declared:
enum Enum1; //Illegal in C++ and C++0x; no size is explicitly specified.
enum Enum2 : unsigned int; //Legal in C++0x.
enum class Enum3; //Legal in C++0x, because enum class declarations have a default type of "int".
enum class Enum4: unsigned int; //Legal C++0x.
enum Enum2 : unsigned short; //Illegal in C++0x, because Enum2 was previously declared with a different type.
Angle bracket
Standard C++'s parser defines ">>" as the right shift operator, in all cases. However, in template definitions, this is almost always the wrong way to interpret two right angle brackets.
C++0x will improve the specification of the parser so that multiple right angle brackets will be interpreted as closing the template argument list where it is reasonable. This can be overridden by using parentheses:
template<bool bTest> SomeType;
std::vector<SomeType<1>2>> x1 ; // Interpreted as a std::vector of SomeType<true> 2>,
// which is not legal syntax. 1 is true.
std::vector<SomeType<(1>2)>> x1 ; // Interpreted as std::vector of SomeType<false>,
//which is legal C++0x syntax. (1>2) is false.
Explicit conversion operators
Standard C++ added the explicit keyword as a modifier on constructors to prevent single-argument constructors to be used as implicit type conversion operators. However, this does nothing for actual conversion operators. For example, a smart pointer class may have an operator bool() to allow it to act more like a primitive pointer: if it includes this conversion, it can be tested with if(smart_ptr_variable) (which would be true if the pointer was non-null and false otherwise). However, this allows other, unintended conversions as well. Because C++ bool is defined as an arithmetic type, it can be implicitly converted to integral or even floating-point types, which allows for mathematical operations that are not intended by the user.
In C++0x, the explicit keyword can now be applied to conversion operators. As with constructors, it prevents the use of those conversion functions in implicit conversions. However, language contexts that specifically require a boolean value (the conditions of if-statements and loops, as well as operands to the logical operators) count as explicit conversions and can thus use a bool conversion operator.
Template typedefs
In standard C++, it is only possible to define a template typedef if all of the template parameters are defined. It is not possible to create a typedef with undefined template parameters. For example:
template< typename first, typename second, int third>
class SomeType;
template< typename second>
typedef SomeType<OtherType, second, 5> TypedefName; //Illegal in C++
This will not compile.
C++0x will add this ability with the following syntax:
template< typename first, typename second, int third>
class SomeType;
template< typename second>
using TypedefName = SomeType<OtherType, second, 5>;
Transparent garbage collection
C++0x will not feature transparent garbage collection directly. Instead, the C++0x standard will include features that will make it easier to implement garbage collection in C++.
Full garbage collection support has been remanded to a later version of the standard or a Technical Report.
Unrestricted unions
In Standard C++ there are restrictions on what type of objects can be members of a union. For example, unions cannot contain any objects which define a non-trivial constructor. Many of the limitations imposed on unions seem unnecessary, so in the next standard all restrictions on the types of members of unions will be removed, with the exception of reference types. These changes will make unions easier to use, more powerful, and much more useful. [1]
This is a simple example of a union permitted in C++0x:
struct point
{
point() {}
point(int x, int y): x_(x), y_(y) {}
int x_, y_;
};
union
{
int z;
double w;
point p; // Illegal in C++; point has a non-trivial constructor. However, this is legal in C++0x.
};
The changes will not break any existing code since they only involve relaxing current rules.
Core language functionality improvements
These features allow the language to do things in the language which were previously impossible, exceedingly verbose, or required non-portable libraries.
Variadic templates
Prior to C++0x, templates (classes and functions) can only take a set number of arguments that have to be specified when a template is first declared. C++0x will allow template definitions to take an arbitrary number of arguments of any type.
template<typename... Values> class tuple;
This template class tuple will take any number of typenames as its template parameters:
class tuple<int, std::vector<int>, std::map<std::string, std::vector<int>>> someInstanceName;
The number of arguments can be 0, so class tuple<> someInstanceName will work as well.
If one does not want to have a variadic template that takes 0 arguments, then this definition will work as well:
template<typename First, typename... Rest> class tuple;
Variadic templates may also apply to functions, thus not only providing a type-safe add-on to variadic functions (such as printf) - but also allowing a printf-like function to process non-trivial objects.
template<typename... Params> void printf(const std::string &strFormat, Params... parameters);
Note the use of the ... operator on the right of the type Params in the function signature, rather than the left as in the template specification. When the ... operator is on the left of the type, as in the template specification, it is the "pack" operator. This signifies that the type can be zero or more of them. When the operator is to the right of the type, it is the "unpack" operator. This causes the replication of the operations done on that type, one for each of the types that were packed with the pack operator. In the above example, the function printf will be given a parameter for each of the types packed in Params.
The use of variadic templates is often recursive. The variadic parameters themselves are not readily available to the implementation of a function or class. As such, the typical mechanism for defining something like a C++0x variadic printf replacement would be as follows:
void printf(const char *s)
{
while (*s)
{
if (*s == '%' && *(++s) != '%')
throw std::runtime_error("invalid format string: missing arguments");
std::cout << *s++;
}
}
template<typename T, typename... Args>
void printf(const char* s, T value, Args... args)
{
while (*s)
{
if (*s == '%' && *(++s) != '%')
{
std::cout << value;
printf(*s ? ++s : s, args...); // call even when *s == 0 to detect extra arguments
return;
}
std::cout << *s++;
}
throw std::logic_error("extra arguments provided to printf");
}
This is a recursive call. Notice that the variadic template version of printf calls itself, or in the event that args is empty, calls the simple case.
There is no simple mechanism to iterate over the values of the variadic template. However, using the unpack operator, the template arguments can be unpacked virtually anywhere.
For example, a class can specify the following:
template <typename... BaseClasses> class ClassName : public BaseClasses...
{
public:
ClassName (BaseClasses&&... baseClasses) : BaseClasses(baseClasses)... {}
}
The unpack operator will replicate the types for the base classes of ClassName, such that this class will be derived from each of the types passed in. Also, the constructor must take a reference to each base class, so as to initialize the base classes of ClassName.
With regard to function templates, the variadic parameters can be forwarded. When combined with r-value references (see below), this allows for perfect forwarding:
template<typename TypeToConstruct> struct SharedPtrAllocator
{
template<typename ...Args> tr1::shared_ptr<TypeToConstruct> ConstructWithSharedPtr(Args&&... params)
{
return tr1::shared_ptr<TypeToConstruct>(new TypeToConstruct(std::forward<Args>(params)...));
}
}
This unpacks the argument list into the constructor of TypeToConstruct. The std::forward<Args>(params) syntax is the syntax that perfectly forwards arguments as their proper types, even with regard to rvalue-ness, to the constructor. The unpack operator will propagate the forwarding syntax to each parameter. This particular factory function automatically wraps the allocated memory in a tr1::shared_ptr for a degree of safety with regard to memory leaks.
Additionally, the number of arguments in a template parameter pack can be determined as follows:
template<typename ...Args> struct SomeStruct
{
static const int size = sizeof...(Args);
}
The syntax SomeStruct<Type1, Type2>::size will be 2, while SomeStruct<>::size will be 0.
New string literals
Standard C++ offers two kinds of string literals. The first kind, contained within double quotes, produces a null-terminated array of type const char. The second kind, defined as, L"", produces a null-terminated array of type const wchar_t, where wchar_t is a wide-character. Neither literal type offers support for Unicode-encoded string literals.
For the purpose of enhancing support for Unicode in C++ compilers, the definition of the type char has been modified to be both at least the size necessary to store an eight-bit coding of UTF-8 and large enough to contain any member of the compiler's basic execution character set. It was previously defined as only the latter.
There are three Unicode encodings that C++0x will support: UTF-8, UTF-16, and UTF-32. In addition to the previously noted changes to the definition of char, C++0x will add two new character types: char16_t and char32_t. Each of these is designed to store UTF-16 and UTF-32 respectively.
The following shows how to create string literals for each of these encodings:
u8"I'm a UTF-8 string."
u"This is a UTF-16 string."
U"This is a UTF-32 string."
The type of the first string is the usual const char[]
. The type of the second string is const char16_t[]
. The type of the third string is const char32_t[]
.
When building Unicode string literals, it is often useful to insert Unicode codepoints directly into the string. To do this, C++0x will allow the following syntax:
u8"This is a Unicode Character: \u2018."
u"This is a bigger Unicode Character: \u2018."
U"This is a Unicode Character: \u2018."
The number after the '\u' is a hexadecimal number; it does not need the usual '0x' prefix. The identifier '\u' represents a 16-bit Unicode codepoint; to enter a 32-bit codepoint, use '\U' and a 32-bit hexadecimal number. Only valid Unicode codepoints can be entered. For example, codepoints on the range U+D800—U+DFFF are forbidden, as they are reserved for surrogate pairs in UTF-16 encodings.
It is also sometimes useful to avoid escaping strings manually, particularly for using literals of XML files or scripting languages. C++0x will provide a raw string literal:
R"[The String Data \ Stuff " ]" R"delimiter[The String Data \ Stuff " ]delimiter"
In the first case, everything between the [
]
brackets is part of the string. The "
and \
characters do not need to be escaped. In the second case, the "delimiter[
starts the string, and it only ends when ]delimiter"
is reached. The string delimiter
can be any arbitrary string, which allows the user to use ]
characters within raw string literals.
Raw string literals can be combined with the wide literal or any of the Unicode literals:
u8R"XXX[I'm a "raw UTF-8" string.]XXX"
uR"*@[This is a "raw UTF-16" string.]*@"
UR"[This is a "raw UTF-32" string.]"
User-defined literals
Standard C++ provides a number of literals. The characters, "12.5" are a literal that is resolved by the compiler as a type double with the value of 12.5. However, the addition of the suffix "f", as in "12.5f", creates a value of type float that contains the value 12.5. The suffix modifiers for literals is fixed by the C++ specification, and C++ code cannot create new literal modifiers.
C++0x will also include the ability for the user to define new kinds of literal modifiers that will construct objects based on the string of characters that the literal modifies.
Literals transformation is redefined into two distinct phases: raw and cooked. A raw literal is a sequence of characters of some specific type, while the cooked literal is of a separate type. The C++ literal 1234, as a raw literal, is this sequence of characters '1', '2', '3', '4'. As a cooked literal, it is the integer 1234. The C++ literal 0xA in raw form is '0', 'x', 'A', while in cooked form it is the integer 10.
Literals can be extended in both raw and cooked forms, with the exception of string literals, which can only be processed in cooked form. This exception is due to the fact that strings have prefixes that affect the specific meaning and type of the characters in question.
All user-defined literals are suffixes; defining prefix literals is not possible. Suffixes that do not start with an underscore are reserved by the language for future use.
User-defined literals processing the raw form of the literal are defined as follows:
OutputType operator "" _Suffix(const char *literal_string);
OutputType someVariable = "1234"_Suffix;
The second statement executes the code defined by the user-defined literal function. This function is passed "1234" as a C-style string, so it has a null terminator.
An alternative mechanism for processing raw literals is through a variadic template:
template<char...> OutputType operator "" _Suffix();
OutputType someVariable = "1234"_Suffix;
This instantiates the literal processing function as operator""_Suffix<'1', '2', '3', '4'>. In this form, there is no terminating null character to the string. The main purpose to doing this is to use C++0x's constexpr keyword and the compiler to allow the literal to be transformed entirely at compile time, assuming OutputType is a constexpr-constructable and copyable type, and the literal processing function is a constexpr function.
For cooked literals, the type of the cooked literal is used, and there is no alternative template form:
OutputType operator "" _Suffix(int the_value);
OutputType someVariable = "1234"_Suffix;
For string literals, the following are used, in accordance with the previously mentioned new string prefixes:
OutputType operator "" _Suffix(const char * string_values, size_t num_chars);
OutputType operator "" _Suffix(const wchar_t * string_values, size_t num_chars);
OutputType operator "" _Suffix(const char16_t * string_values, size_t num_chars);
OutputType operator "" _Suffix(const char32_t * string_values, size_t num_chars);
OutputType someVariable = "1234"_Suffix; //Calls the const char * version
OutputType someVariable = u8"1234"_Suffix; //Calls the const char * version
OutputType someVariable = L"1234"_Suffix; //Calls the const wchar_t * version
OutputType someVariable = u"1234"_Suffix; //Calls the const char16_t * version
OutputType someVariable = U"1234"_Suffix; //Calls the const char32_t * version
Character literals are defined similarly.
Multitasking memory model
The C++ standard committee plans to standardise support for multithreaded programming.
There are two parts involved: defining a memory model which will allow multiple threads to co-exist in a program, and defining support for interaction between threads. The second part will be provided via library facilities, see threading facilities.
A memory model is necessary in order to dictate under which circumstances multiple threads may access the same memory location. A program which adheres to the rules is guaranteed to execute correctly, but a program which breaks the rules may have unexpected behavior due to compiler optimizations and problems with memory coherence.
Thread-local storage
In a multi-threaded environment, it is common for every thread to have some unique variables. This already happens for the local variables of a function, but it does not happen for global and static variables.
A new thread-local storage duration (in addition to the existing static, dynamic and automatic) has been proposed for the next standard. Thread local storage will be indicated by the storage specifier thread_local
.
Any object which could have static storage duration (i.e. lifetime spanning the entire execution of the program) may be given thread-local duration instead. The intent is that like any other static-duration variable, a thread-local object can be initialized using a constructor and destroyed using a destructor.
Defaulting/deleting of standard functions on C++ objects
In standard C++, the compiler will provide, for objects that do not provide for themselves, a default constructor, a copy constructor, a copy assignment operator operator=, and a destructor. As mentioned, the user can override these defaults by defining their own version. C++ also defines several global operators (such as operator=, and operator new) that work on all classes, which the user can override.
The problem is that there are very few controls over the creation of these defaults. Making a class inherently non-copyable, for example, requires declaring a private copy constructor and copy assignment operator and not defining them. Attempting to use these functions will cause a compiler or linker error. However, this is not an ideal solution.
Further, in the case of the default constructor, it is useful to want to explicitly tell the compiler to generate it. The compiler will not generate a default constructor if the object is defined with any constructors. This is useful in many cases, but it is also useful to be able to have both a specialized constructor and the compiler-generated default.
C++0x will allow the explicit use, or disuse, of these standard object functions. For example, the following type explicitly declares that it is using the default constructor:
struct SomeType
{
SomeType() = default; //The default constructor is explicitly stated.
SomeType(OtherType value);
};
Alternatively, certain features can be explicitly disabled. For example, the following type is non-copyable:
struct NonCopyable
{
NonCopyable & operator=(const NonCopyable&) = delete;
NonCopyable(const NonCopyable&) = delete;
NonCopyable() = default;
};
A type can be made impossible to allocate with operator new:
struct NonNewable
{
void *operator new(std::size_t) = delete;
};
This object can only ever be allocated as a stack object or as a member of another type. It cannot be directly heap allocated without non-portable trickery. (Since placement new is the only way to call a constructor on user-allocated memory and this use has been forbidden as above, the object cannot be properly constructed.)
The = delete
specifier can be used to prohibit calling any function, which can be used to disallow calling a member function with particular parameters. For example:
struct NoDouble
{
void f(int i);
void f(double) = delete;
};
An attempt to call f()
with a double
will be rejected by the compiler, instead of performing a silent conversion to int
. This can be generalized to disallow calling the function with any type other than int
as follows:
struct OnlyInt
{
void f(int i);
template<class T> void f(T) = delete;
};
Type long long int
On 32-bit systems, a long long int
is an integer type that has at least 64 useful bits. C99 introduced this type to standard C and it is supported as an extension by most C++ compilers. (Indeed, some compilers supported it before its introduction to C99.)[citation needed] C++0x will add this type to standard C++.
Static assertions
The C++ standard provides two methods to test assertions: the macro assert
and the preprocessor directive #error
. However, neither is appropriate for use in templates: the macro tests the assertion at execution-time, while the preprocessor directive tests the assertion during preprocessing, which happens before instantiation of templates. Neither is appropriate for testing properties that are dependent on template parameters.
The new utility introduces a new way to test assertions at compile-time, using the new keyword static_assert
.
The declaration assumes the following form:
static_assert( constant-expression, error-message ) ;
Here are some examples of how static_assert
can be used:
static_assert( 3.14 < GREEKPI && GREEKPI < 3.15, "GREEKPI is inaccurate!" ) ;
template< class T >
struct Check
{
static_assert( sizeof(int) <= sizeof(T), "T is not big enough!" ) ;
} ;
When the constant expression is false
the compiler produces an error message. The first example represents an alternative to the preprocessor directive #error
, in contrast in the second example the assertion is checked at every instantiation of the template class Check
.
Static assertions are useful outside of templates as well. For instance, a particular implementation of an algorithm might depend on the size of a long long
being larger than an int
, something the standard does not guarantee. Such an assumption is valid on most systems and compilers, but not all.
Allow 'sizeof' to work on members of classes without an explicit object
In standard C++, the sizeof operation can be used on types and objects. But it cannot be used to do the following:
struct SomeType { OtherType member; };
sizeof(SomeType::member); //Does not work with C++03. Okay with C++0x
This should return the size of OtherType. C++03 does not allow this, so it is a compile error. C++0x will allow it.
C++ standard library changes
A number of new features will be introduced in the C++0x standard library. Many of these can be implemented under the current standard, but some rely (to a greater or lesser extent) on new C++0x core features.
A large part of the new libraries are defined in the document C++ Standards Committee's Library Technical Report (called TR1), which was published in 2005. Various full and partial implementations of TR1 are currently available using the namespace std::tr1
. For C++0x they will be moved to namespace std
. However, as TR1 features are brought into the C++0x standard library, they are upgraded where appropriate with C++0x language features that were not available in the initial TR1 version. Also, they may be enhanced with features that were possible under C++03, but were not part of the original TR1 specification.
The committee intends to create a second technical report (called TR2) after the standardization of C++0x is complete. Library proposals which are not ready in time for C++0x will be put into TR2 or further technical reports.
The following proposals are under way for C++0x.
Upgrades to standard library components
C++0x offers a number of new language features that the currently existing standard library components can benefit from. For example, most standard library containers can benefit from Rvalue reference based move constructor support, both for quickly moving heavy containers around and for moving the contents of those containers to new memory locations. The standard library components will be upgraded with new C++0x language features where appropriate. These include, but are not necessarily limited to:
- Concepts
- Rvalue references and the associated move support
- Support for the UTF-16 and UTF-32 character types
- Variadic templates (coupled with Rvalue references to allow for perfect forwarding)
- Compile-time constant expressions
- Decltype
- Explicit conversion operators
- Default/Deleted functions
Additionally, much time has passed since C++ was standardized. A great deal of code using the standard library has been written; this has revealed portions of the standard libraries that could use some improvement. Among the many areas of improvement being considered are standard library allocators. A new scope-based model of allocators will be included in the C++0x to supplement the current model.
Threading facilities
While the C++0x language will provide a memory model that supports threading, the primary support for actually using threading will come with the C++0x standard library.
A thread class (std::thread
) will be provided which will take a function object — and an optional series of arguments to pass to it — to run in the new thread. It will be possible to cause a thread to halt until another executing thread completes, providing thread joining support through the std::thread::join()
member function. Access will also be provided, where feasible, to the underlying native thread object(s) for platform specific operations by the std::thread::native_handle()
member function.
For synchronization between threads, appropriate mutexes (std::mutex
, std::recursive_mutex
, etc.) and condition variables (std::condition_variable
and std::condition_variable_any
) will be added to the library. This will be accessible through RAII locks (std::lock_guard
and std::unique_lock
) and locking algorithms for easy use.
For high-performance low-level work it is sometimes necessary to communicate between threads without the overhead of mutexes. This is achieved using atomic operations on memory locations, together with appropriate memory barriers. An atomics library will be provided which will allow specifying the minimum synchronization necessary for an operation.
The C++0x thread library will also include futures for passing asynchronous results between threads, and std::packaged_task
for wrapping up a function call that can generate such an asynchronous result.
Further high-level threading facilities such as thread pools have been remanded to a future C++ technical report. They will not be a part of C++0x, but their eventual implementation is expected to be built entirely on top of the thread library features.
Tuple types
Tuples are collections composed of heterogeneous objects of pre-arranged dimensions. A tuple can be considered a generalization of a struct's member variables.
The C++0x version of the TR1 tuple type will benefit from C++0x features like variadic templates. The TR1 version required an implementation-defined maximum number of contained types, and required substantial macro trickery to implement reasonably. By contrast, the implementation of the C++0x version requires no explicit implementation-defined maximum number of types. Though compilers will almost certainly have an internal maximum recursion depth for template instantiation (which is normal), the C++0x version of tuples will not expose this value to the user.
Using variadic templates, the declaration of the tuple class looks as follows:
template <class ...Types> class tuple;
An example of definition and use of the tuple type:
typedef tuple< int, double, long &, const char * > test_tuple ;
long lengthy = 12 ;
test_tuple proof( 18, 6.5, lengthy, "Ciao!" ) ;
lengthy = get<0>(proof) ; // Assign to 'lengthy' the value 18.
get<3>(proof) = " Beautiful!" ; // Modify the tuple’s fourth element.
It’s possible to create the tuple proof
without defining its contents, but only if the tuple elements' types possess default constructors. Moreover, it’s possible to assign a tuple to another tuple: if the two tuples’ types are the same, it is necessary that each element type possesses a copy constructor; otherwise, it is necessary that each element type of the right-side tuple is convertible to that of the corresponding element type of the left-side tuple or that the corresponding element type of the left-side tuple has a suitable constructor.
typedef tuple< int , double, string > tuple_1 t1 ;
typedef tuple< char, short , const char * > tuple_2 t2( 'X', 2, "Hola!" ) ;
t1 = t2 ; // Ok, first two elements can be converted,
// the third one can be constructed from a 'const char *'.
Relational operators are available (among tuples with the same number of elements), and two expressions are available to check a tuple’s characteristics (only during compilation):
tuple_size<T>::value
returns the elements’ number of the tupleT
,tuple_element<I, T>::type
returns the type of the object numberI
of the tupleT
.
Hash tables
Including hash tables (unordered associative containers) in the C++ standard library is one of the most recurring requests. It was not adopted in the current standard due to time constraints only. Although this solution is less efficient than a balanced tree in the worst case (in the presence of many collisions), it performs better in many real applications.
Collisions will be managed only through linear chaining because the committee doesn’t consider opportune to standardize solutions of open addressing that introduce quite a lot of intrinsic problems (above all when erasure of elements is admitted). To avoid name clashes with non-standard libraries that developed their own hash table implementations, the prefix “unordered” will be used instead of “hash”.
The new utility will have four types of hash tables, differentiated by whether or not they accept elements with the same key (unique keys or equivalent keys), and whether they map each key to an associated value.
Type of hash table | Arbitrary mapped type | Equivalent keys |
---|---|---|
unordered_set | ||
unordered_multiset | • | |
unordered_map | • | |
unordered_multimap | • | • |
New classes fulfill all the requirements of a container class, and have all the methods necessary to access elements: insert
, erase
, begin
, end
.
This new utility doesn’t need any C++ language core extensions (though the implementation will take advantage of various C++0x language features), only a small extension of the header <functional>
and the introduction of headers <unordered_set>
and <unordered_map>
. No other changes to any existing standard classes are needed, and it doesn’t depend on any other extensions of the standard library.
Although it's being considered that if the "concepts" feature is ready and working, the existing "map" and "set" symbols will be reused, as there's no point in separate "unordered" containers. To create a "hash map", for example, it will be enough to declare it as
std::map<std::string, int, std::hash>
, which would be the same as the hash_map extension: hash_map<std::string, int>
, where third parameter defaults to "hash".
Regular expressions
Many more or less standardized libraries were created to manage regular expressions. Since the use of these algorithms is very common, the standard library will include them using all potentialities of an object oriented language.
The new library, defined in the new header <regex>
, is made of a couple of new classes:
- regular expressions are represented by instance of the template class
basic_regex
; - occurrences are represented by instance of the template class
match_results
.
The function regex_search
is used for searching, while for ‘search and replace’ the function regex_replace
is used which returns a new string.
The algorithms regex_search
and regex_replace
take a regular expression and a string and write the occurrences found in the struct match_results
.
Here is an example on the use of match_results
:
const char *reg_esp = "[ ,.\\t\\n;:]" ; // List of separator characters.
regex rgx(reg_esp) ; // 'regex' is an instance of the template class
// 'basic_regex' with argument of type 'char'.
cmatch match ; // 'cmatch' is an instance of the template class
// 'match_results' with argument of type 'const char *'.
const char *target = "Polytechnic University of Turin " ;
// Identifies all words of 'target' separated by characters of 'reg_esp'.
if( regex_search( target, match, rgx ) )
{
// If words separated by specified characters are present.
const size_t n = match.size();
for( size_t a = 0 ; a < n ; a++ )
{
string str( match[a].first, match[a].second ) ;
cout << str << "\n" ;
}
}
Note the use of double backslashes, because the C++ preprocessor uses backslash as an escape character. The C++0x raw string feature could be used to avoid the problem.
The library “regex
” doesn’t need alteration of any existing header (though it will use them where appropriate) and no extension of the core language.
Enjoy ept;)
General-purpose smart pointers
These pointers are taken from the TR1 smart pointers.
The shared_ptr
is a reference-counted pointer that acts as much as possible like a regular C++ data pointer. The TR1 implementation lacked certain pointer features such as aliasing and pointer arithmetic, but the C++0x version will add these.
The shared pointer will automatically destroy its contents only when there are no shared pointers referencing the object originally created for the shared pointer.
A weak_ptr
is a reference to an object referenced by a shared_ptr
that can determine if that object has been deleted or not. weak_ptr
itself cannot be dereferenced; accessing the actual pointer requires the creation of a shared_ptr
object. This can be done in one of two ways. The shared_ptr
class has a constructor that takes a weak_ptr
and the weak_ptr
class has a lock
member function that returns a shared_ptr
. The weak_ptr
does not own the object it references, and thus the existence of a weak_ptr
will not prevent the deletion of the object.
Here it is an example of use of shared_ptr
:
int main( )
{
shared_ptr<double> p_first(new double) ;
{
shared_ptr<double> p_copy = p_first ;
*p_copy = 21.2;
} // Destruction of 'p_copy' but not of the allocated double.
return 0; // Destruction of 'p_first' and accordingly of the allocated double.
}
unique_ptr
will be provided as a replacement for auto_ptr
which will be deprecated. It provides all the features of auto_ptr
with the exception of unsafe implicit moving from lvalues. Unlike auto_ptr
, unique_ptr
can be used with the C++0x move-aware containers.
Extensible random number facility
The C standard library provides the ability to generate pseudorandom numbers through the function rand
. However, the algorithm is delegated entirely to the library vendor. C++ inherited this functionality with no changes, but C++0x will provide a new method for generating pseudorandom numbers.
C++0x's random number functionality is split into two parts: a generator engine that contains the random number generator's state and produces the pseudorandom numbers; and a distribution, which determines the range and mathematical distribution of the outcome. These two are combined to form a random number generator object.
Unlike the C standard rand
, the C++0x mechanism will come with three generator engine algorithms, each with its own strengths and weaknesses:
template class | int/float | quality | speed | size of state* |
---|---|---|---|---|
linear_congruential | int | low | medium[citation needed] | 1 |
subtract_with_carry | both | medium | fast | 25 |
mersenne_twister | int | good | fast | 624 |
C++0x will also provide a number of standard distributions: uniform_int
, bernoulli_distribution
, geometric_distribution
, poisson_distribution
, binomial_distribution
, uniform_real
, exponential_distribution
, normal_distribution
, and gamma_distribution
.
The generator and distributions are combined as in the following example:
std::uniform_int<int> distribution( 0, 99 ) ;
std::mt19937 engine ;
std::variate_generator<mt19937, uniform_int<int>> generator( engine, distribution );
int random = generator() ; // Assign a value among 0 and 99.
The interface used by std::variate_generator
is well defined; the user can create both generator engines and distribution objects to use with this class.
Wrapper reference
A wrapper reference is obtained from an instance of the template class reference_wrapper
. Wrapper references are similar to normal references (‘&’) of the C++ language. To obtain a wrapper reference from any object the template class ref
is used (for a constant reference cref
is used).
Wrapper references are useful above all for template functions, when we need to obtain references to parameters rather than copies:
// This function will obtain a reference to the parameter 'r' and increase it.
void f( int &r ) { r++ ; }
// Template function.
template< class F, class P > void g( F f, P t ) { f(t) ; }
int main()
{
int i = 0 ;
g( f, i ) ; // 'g<void ( int &r ), int>' is instantiated
// then 'i' will not be modified.
cout << i << endl ; // Output -> 0
g( f, ref(i) ) ; // 'g<void(int &r),reference_wrapper<int>>' is instanced
// then 'i' will be modified.
cout << i << endl ; // Output -> 1
}
This new utility will be added to the existing <utility>
header and doesn’t need further extensions of the C++ language.
Polymorphous wrappers for function objects
Polymorphous wrappers for function objects (also called “polymorphic function object wrappers”) are similar to function pointers in semantics and syntax, but are less tightly bound and can indiscriminately refer to anything which can be called (function pointers, member function pointers, or functors) whose arguments are compatible with those of the wrapper.
Through the next example it is possible to understand its characteristics:
function<int ( int, int )> pF ; // Wrapper creation using
// template class 'function'.
plus<int> add ; // 'plus' is declared as 'template<class T> T plus( T, T ) ;'
// then 'add' is type 'int add( int x, int y )'.
pF = &add ; // OK - Parameters and return types are the same.
int a = pF( 1, 2 ) ; // NOTE: if the wrapper 'pF' does not refer to any function,
// the exception 'std::bad_function_call' is thrown.
function<bool ( short, short )> pG ;
if( !pG ) // Always true because 'pG' has not yet
// been assigned a function.
{
bool adjacent( long x, long y ) ;
pG = &adjacent ; // OK - Parameters and return types are convertible.
struct test
{
bool operator()( short x, short y ) ;
} car ;
pG = ref(car) ; // 'ref' is a template function that returns the wrapper
// of member function 'operator()' of struct 'car'.
}
pF = pG ; // OK - Parameters and return types are convertible.
The template class function
will be defined inside the header <functional>
, and doesn't require any changes to the C++ language.
Type traits for metaprogramming
Metaprogramming consists of creating a program that creates or modifies another program (or itself). This can happen during compilation or during execution. The C++ Standards Committee has decided to introduce a library that allows metaprogramming during compilation through templates.
Here is an example of what is possible, using the actual standard, through metaprogramming: a recursion of template instances for exponential calculus.
template< int B, int N >
struct Pow
{
// recursive call and recombination.
enum{ value = B*Pow< B, N-1 >::value } ;
} ;
template< int B > struct Pow< B, 0 > // ''N == 0'' condition of termination.
{
enum{ value = 1 } ;
} ;
int quartic_of_three = Pow< 3, 4 >::value ;
Many algorithms can operate on different types of data; C++'s templates support generic programming and make code more compact and useful. Nevertheless it is common for algorithms to need information on the data types being used. This information can be extracted during instantiation of a template class using type traits.
Type traits can identify the category of an object and all the characteristic of a class (or of a struct). They are defined in the new header <type_traits>
.
In the next example there is the template function ‘elaborate’ that, depending on the given data types, will instantiate one of the two proposed algorithms (algorithm.do_it
).
// First way of operating.
template< bool B > struct algorithm
{
template< class T1, class T2 > int do_it( T1 &, T2 & ) { /*...*/ }
} ;
// Second way of operating.
template<> struct algorithm<true>
{
template< class T1, class T2 > int do_it( T1, T2 ) { /*...*/ }
} ;
// Instantiating 'elaborate' will automatically instantiate the correct way to operate.
template< class T1, class T2 > int elaborate( T1 A, T2 B )
{
// Use the second way only if 'T1' is an integer and if 'T2' is
// in floating point, otherwise use the first way.
return algorithm< is_integral<T1>::value && is_floating_point<T2>::value >::do_it( A, B ) ;
}
Through type traits, defined in header <type_transform>
, it’s also possible to create type transformation operations (static_cast
and const_cast
are insufficient inside a template).
This type of programming produces elegant and concise code; however the weak point of these techniques is the debugging: uncomfortable during compilation and very difficult during program execution.
Uniform method for computing return type of function objects
Determining the return type of a template function object at compile-time is not intuitive, particularly if the return value depends on the parameters of the function. As an example:
struct clear
{
int operator()( int ) ; // The parameter type is
double operator()( double ) ; // equal to the return type.
} ;
template< class Obj > class calculus
{
public:
template< class Arg > Arg operator()( Arg& a ) const
{
return member(a) ;
}
private:
Obj member ;
} ;
Instantiating the class template calculus<clear>
, the function object of calculus
will have always the same return type as the function object of clear
. However, given class confused
below:
struct confused
{
double operator()( int ) ; // The parameter type is NOT
int operator()( double ) ; // equal to the return type.
} ;
Attempting to instantiate calculus<confused>
will cause the return type of calculus
to not be the same as that of class confused
. The compiler may generate warnings about the conversion from int
to double
and vice-versa.
TR1 introduces, and C++0x adopts, the template class std::result_of
that allows to determine and use the return type of a function object for every declaration. The object calculus_ver2
uses the std::result_of
object to derive the return type of the function object:
template< class Obj >
class calculus_ver2
{
public:
template< class Arg >
typename std::result_of<Obj(Arg)>::type operator()( Arg& a ) const
{
return member(a) ;
}
private:
Obj member ;
} ;
In this way in instances of function object of calculus_ver2<confused>
there are no conversions, warnings, or errors.
The only change from the TR1 version of std::result_of
is that the TR1 version allowed an implementation to fail to be able to determine the result type of a function call. Due to changes to C++ for supporting decltype
, the C++0x version of std::result_of
no longer needs these special cases; implementations are required to compute a type in all cases.
See also
- TR1 proposed C++ extension
- C99, new standard for the C programming language
- ConceptGCC
References
C++ Standards Committee papers
- ISO/IEC DTR 19768 (October 4, 2008) Doc No: 2798 Working Draft, Standard for Programming Language C++
- ISO/IEC DTR 19768 (May 19, 2008) Doc No: 2606 Working Draft, Standard for Programming Language C++
- ISO/IEC DTR 19768 (April 29, 2008) Doc No: 2597 State of C++ Evolution (pre-Antipolis 2008 Meeting)
- ISO/IEC DTR 19768 (March 07, 2008) Doc No: N2565 State of C++ Evolution (post-Bellevue 2008 Meeting)
- ISO/IEC DTR 19768 (February 04, 2008) Doc No: N2507 State of C++ Evolution (pre-Bellevue 2008 Meeting)
- ISO/IEC DTR 19768 (October 23, 2007) Doc No: N2432 State of C++ Evolution (post-Kona 2007 Meeting)
- ISO/IEC DTR 19768 (August 7, 2007) Doc No: N2389 State of C++ Evolution (pre-Kona 2007 Meetings)
- ISO/IEC DTR 19768 (July 29, 2007) Doc No: N2336 State of C++ Evolution (Toronto 2007 Meetings)
- ISO/IEC DTR 19768 (June 25, 2007) Doc No: N2291 State of C++ Evolution (Toronto 2007 Meetings)
- ISO/IEC DTR 19768 (May 3, 2007) Doc No: N2228 State of C++ Evolution (Oxford 2007 Meetings)
- ISO/IEC DTR 19768 (January 12, 2007) Doc No: N2142 State of C++ Evolution (between Portland and Oxford 2007 Meetings)
- ISO/IEC DTR 19768 (October 22, 2007) Doc No: N2461 Working Draft, Standard for programming Language C++
- ISO/IEC DTR 19768 (June 24, 2005) Doc No: N1836 Draft Technical Report on C++ Library Extensions
- Lawrence Crowl (May 2, 2005) Doc No: N1815 ISO C++ Strategic Plan for Multithreading
- Detlef Vollmann (June 24, 2005) Doc No: N1834 A Pleading for Reasonable Parallel Processing Support in C++
- Lawrence Crowl (May 2, 2007) Doc No: N2280 Thread-Local Storage
- Jan Kristoffersen (October 21, 2002) Doc No: N1401 Atomic operations with multi-threaded environments
- Hans Boehm, Nick Maclaren (April 21, 2002) Doc No: N2016 Should volatile Acquire Atomicity and Thread Visibility Semantics?
- Lois Goldthwaite (October 5, 2007) Doc No: N2437 Explicit Conversion Operators
- Alan Talbot, Lois Goldthwaite, Lawrence Crowl, Jens Maurer (February 29, 2008) Doc No: N2544 Unrestricted unions
- Francis Glassborow, Lois Goldthwaite (November 5, 2004) Doc No: N1717 explicit class and default definitions
- Bjarne Stroustrup, Gabriel Dos Reis (December 11, 2005) Doc No: N1919 Initializer lists
- Herb Sutter, Francis Glassborow (April 6, 2006) Doc No: N1986 Delegating Constructors (revision 3)
- Michel Michaud, Michael Wong (October 6, 2004) Doc No: N1898 Forwarding and inherited constructors
- Bronek Kozicki (September 9, 2004) Doc No: N1676 Non-member overloaded copy assignment operator
- R. Klarer, J. Maddock, B. Dawes, H. Hinnant (October 20, 2004) Doc No: N1720 Proposal to Add Static Assertions to the Core Language (Revision 3)
- V Samko; J Willcock, J Järvi, D Gregor, A Lumsdaine (February 26, 2006) Doc No: N1968 Lambda expressions and closures for C++
- J. Järvi, B. Stroustrup, D. Gregor, J. Siek, G. Dos Reis (September 12, 2004) Doc No: N1705 Decltype (and auto)
- B. Stroustrup, G. Dos Reis, Mat Marcus, Walter E. Brown, Herb Sutter (April 7, 2003) Doc No: N1449 Proposal to add template aliases to C++
- Douglas Gregor, Jaakko Järvi, Gary Powell (September 10, 2004) Doc No: N1704 Variadic Templates: Exploring the Design Space
- Gabriel Dos Reis, Bjarne Stroustrup (October 20, 2005) Doc No: N1886 Specifying C++ concepts
- Daveed Vandevoorde (January 14, 2005) Doc No: N1757 Right Angle Brackets (Revision 2)
- Walter E. Brown (October 18, 2005) Doc No: N1891 Progress toward Opaque Typedefs for C++0X
- J. Stephen Adamczyk (April 29, 2005) Doc No: N1811 Adding the long long type to C++ (Revision 3)
- Chris Uzdavinis, Alisdair Meredith (August 29, 2005) Doc No: N1827 An Explicit Override Syntax for C++
- Herb Sutter, David E. Miller (October 21, 2004) Doc No: N1719 Strongly Typed Enums (revision 1)
- Matthew Austern (April 9, 2003) Doc No: N1456 A Proposal to Add Hash Tables to the Standard Library (revision 4)
- Doug Gregor (November 8, 2002) Doc No: N1403 Proposal for adding tuple types into the standard library
- John Maddock (March 3, 2003) Doc No: N1429 A Proposal to add Regular Expression to the Standard Library
- P. Dimov, B. Dawes, G. Colvin (March 27, 2003) Doc No: N1450 A Proposal to Add General Purpose Smart Pointers to the Library Technical Report (Revision 1)
- Doug Gregor (October 22, 2002) Doc No: N1402 A Proposal to add a Polymorphic Function Object Wrapper to the Standard Library
- D. Gregor, P. Dimov (April 9, 2003) Doc No: N1453 A proposal to add a reference wrapper to the standard library (revision 1)
- John Maddock (March 3, 2003) Doc No: N1424 A Proposal to add Type Traits to the Standard Library
- Daveed Vandevoorde (April 18, 2003) Doc No: N1471 Reflective Metaprogramming in C++
- Jens Maurer (April 10, 2003) Doc No: N1452 A Proposal to Add an Extensible Random Number Facility to the Standard Library (Revision 2)
- Walter E. Brown (October 28, 2003) Doc No: N1542 A Proposal to Add Mathematical Special Functions to the C++ Standard Library (version 3)
- Douglas Gregor, P. Dimov (April 9, 2003) Doc No: N1454 A uniform method for computing function object return types (revision 1)
Articles
- a b The C++ Source Bjarne Stroustrup (January 2, 2006) A Brief Look at C++0x
- ^ C/C++ Users Journal Bjarne Stroustrup (May, 2005) The Design of C++0x: Reinforcing C++’s proven strengths, while moving into the future
- Web Log di Raffaele Rialdi (September 16, 2005) Il futuro di C++ raccontato da Herb Sutter
- Informit.com (August 5, 2006) The Explicit Conversion Operators Proposal
- Informit.com (July 25, 2006) Introducing the Lambda Library
- Dr. Dobb's Portal Pete Becker (April 11, 2006) Regular Expressions TR1's regex implementation
- Informit.com (July 25, 2006) The Type Traits Library
- Dr. Dobb's Portal Pete Becker (May 11, 2005) C++ Function Objects in TR1
- The C++ Source Howard E. Hinnant, Bjarne Stroustrup, and Bronek Kozicki (March 10, 2008) A Brief Introduction to Rvalue References
- DevX.com Special Report (August 18, 2008) C++0x: The Dawning of a New Standard
External links
- The C++ Standards Committee
- Bjarne Stroustrup's homepage
- C++0X: The New Face of Standard C++
- Herb Sutter's blog coverage of C++0X
- A talk on C++0x given by Bjarne Stroustrup at the University of Waterloo
- A quick and dirty introduction to C++0x (as of November 2007)
- The State of the Language: An Interview with Bjarne Stroustrup (August 15, 2008)
- Working draft for the C++ language, October 4, 2008