C++0x
C++0x is the unofficial name of 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 (TR1) 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. The most recent working draft, N3000, was published in November 2009.
The ISO/IEC JTC1/SC22/WG21 C++ Standards Committee originally aimed to have the new standard published by 2009 (the standard that is today called C++0x would become C++09 at the latest). However, there is now some debate over when the standard will be published. The current schedule is to finish addressing comments to the first committee draft, and issue a second committee draft during the March 2010 standards meeting.[1] The final draft international standard may be issued by the end of 2010, however, WG21 expects it to take six months to a year before the standard is officially published by ISO, leading to its publication by the end of 2011.[2] 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.[3]
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-percent compatible with the existing Standard C++”.[4]
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 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.[5] 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 article, 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 C++, temporaries (termed “rvalues”, as they often lie on the right side of an assignment) are indistinguishable from const T& types. C++0x adds a new reference type called an rvalue reference, identified by T&&, which enables move semantics.
For example, a std::vector<T> is, internally, a wrapper around a C-style array with a size. If a std::vector<T> temporary is created or returned from a function, it can only be stored by creating a new std::vector<T> and having it copy all of the rvalue's data into it. Then the temporary is destroyed, deleting its data. With rvalue references, a “move constructor” of std::vector<T> that takes an rvalue reference to a std::vector<T> can simply copy the pointer to the internal C-style array out of the rvalue into the new std::vector<T>, then leave the rvalue 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 std::vector<T> temporary need only return a std::vector<T>&&. If std::vector<T> has no move constructor, then the copy constructor will be invoked with a const std::vector<T>& as normal, incurring a significant memory allocation.
For safety reasons a named variable will never be considered to be an rvalue even if it's declared as such; in order to get an rvalue the function template std::move<T>() should be used.
Due to the nature of the wording of rvalue references, and to some modification to the wording for lvalue references (regular references), rvalue 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() + 7]; //create an array of 12 integers. illegal C++
This is not legal C++, because GetFive() + 7 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() + 7]; //create an array of 12 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 return 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 accelerationDueToGravity = 9.8;
constexpr double moonGravity = accelerationDueToGravity / 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. 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 template, 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 in the following ways:
std::vector<std::string> v = { "xyzzy", "plugh", "abracadabra" };
std::vector<std::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;
double y;
};
struct AltStruct
{
AltStruct(int x, double y) : x_{x}, y_{y} {}
private:
int x_;
double y_;
};
BasicStruct var1{5, 3.2};
AltStruct var2{2, 4.3};
The initialization of var1 functions exactly as though it were aggregate-initialization, that is, each object will be copy-initialized with each value of the initializer-list. Implicit type conversion will be used where necessary. If no conversion exists, or only a narrowing conversion exists, the program is ill-formed. The initialization of var2 invokes the constructor.
One is also able to do the following:
struct IdString
{
std::string name;
int identifier;
};
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. Therefore, 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 can be 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 = 1; // 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 = c; // 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
In standard C++, iterating over the elements of a list requires a lot of code. Other languages like C# have shortcuts that allow one to write a simple “foreach” statement that automatically walks the list from start to finish.
C++0x will add a similar feature. The statement for will allow for easy iteration over a list of elements:
int my_array[5] = {1, 2, 3, 4, 5};
for(int &x : my_array)
{
x *= 2;
}
This form of for, called the “range-based for”, will iterate over each element in the list. It will work for C-style arrays, initializer lists, and any type that has a begin() and end() function defined for it that returns iterators. All of the standard library containers that have begin/end pairs will work with the range-based for statement.
Lambda functions and expressions
In standard C++, particularly when used with C++ standard library algorithm functions such as sort and find, users 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, and it interrupts 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 an 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(); };
Alternative 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 allowed 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 declaration syntax, with a trailing-return-type:
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;
}
The use of the keyword “auto” in this case means something different from its use in automatic type deduction.
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. The new syntax, however, allows the default value (42) to be expressed in the implementation rather than the interface — a benefit to maintainers of library code since default values for function parameters are “baked in” to call sites, whereas constructor delegation allows the value to be changed without recompilation of the code using the library.
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 or uniform initialization, instead of the equality initialization shown above.
Explicit virtual function overrides
In standard C++, virtual functions can be accidentally overridden in derived classes. For example:
struct base {
virtual void some_func();
};
struct derived : base {
void some_func();
};
What is the intent of derived::some_func? Did the user intentionally override it, or was it an accident? It is also possible for the maintainer of base to add a virtual function that has the same name and signature of a function in a derived class.
C++0x will add support to prevent this. In order to maintain backwards compatibility, this functionality is opt-in. The syntax is as follows:
class B {
typedef B self;
virtual void some_func1();
virtual void some_func2(float);
virtual void some_func3() const;
virtual long some_func4(int);
virtual void f();
virtual void h(int);
void j(int);
void k(int);
};
class D [[base_check]] : public B {
using B::j;
void sone_func1 [[override]] (); // ill-formed: mis-spelled name
void some_func2 [[override]] (double); // ill-formed: bad argument type
void some_func3 [[override]] (); // ill-formed: missing cv-qualification
int some_func4 [[override]] (int); // ill-formed: return type does not match B::some_func4
virtual void f [[override]] (); // OK: overrides B::f
virtual void g(long); // new virtual function introduced
void h(int); // ill-formed: overriding without [[override]]
virtual void h(double); // ill-formed: new virtual function hides void h(int)
virtual void h [[hiding]] (char *); // OK, new virtual function hides base
virtual int j( double ); // OK, using declaration prevents hiding
int k( double ); // ill-formed: name hiding and no using declaration
double k [[hiding]] ( char * ); // OK, hiding is clearly indicated
double m [[hiding]] ( char * ); // ill-formed, hiding is requested, but not present
typedef D self; // ill-formed, new type definition hides the definition in B
};
The [[base_check]] attribute on a class/struct means that any implicit overriding will give rise to a compiler error. Any overriding must be explicitly marked with the [[override]] attribute. The [[hiding]] attribute means that a new virtual function is hiding the base class function.
Null pointer constant
For the purposes of this section and this section alone, every occurrence of “0
” is meant as “a constant expression which evaluates to 0
, which is of type int”. In reality, the constant expression can be of any integral type.
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 commonly expands to either ((void*)0)
or 0
. C++ didn't adopt the same behavior, only allowing 0
as a null pointer constant. 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. The reality that 0
can be of any integral type also affects which function will be called.
C++0x aims to correct this by introducing a new keyword to serve as a distinguished null pointer constant: nullptr
. It will be 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 integral types, except for bool
. While the original proposal specified that an rvalue of type nullptr
should not be convertible to bool
, the core language working group decided that such a conversion would be desirable, for consistency with regular pointer types. The proposed wording changes were unanimously voted into the Working Paper in June 2008.[6]
For backwards compatibility reasons, 0
will remain a valid null pointer constant.
char* pc = nullptr; // OK
int * pi = nullptr; // OK
bool b = nullptr; // OK. b is false.
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. Thus, 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; therefore, 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> class 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 aliases
In standard C++, it is only possible to define a typedef as a synonym for another type, including a synonym for a template specialization with all actual template arguments specified. It is not possible to create a typedef template. 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>;
The using syntax can be also used as type aliasing in C++0x:
typedef void (*PFD)(double); // Old style
using PF = void (*)(double); // New introduced syntax
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 types of objects can be members of a union. For example, unions cannot contain any objects that 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.[7]
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 relax current rules.
Core language functionality improvements
These features allow the language to do things that 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);
The ... operator has two roles: when it occurs to the left of the name of a parameter, it declares a parameter pack. By using the parameter pack, user can bind zero or more arguments to the variadic template parameters. Parameter pack can also be used for non-type parameters.
Another role is when ... operator occurs to the right of a template or function call argument, it unpacks the parameter packs into separate arguments, like the args... in the body of printf
.
The use of variadic templates is often recursive. The variadic parameters themselves are not readily available to the implementation of a function or class. Therefore, 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, 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 template. Notice that the variadic template version of printf calls itself, or (in the event that args... is empty) calls the base case.
There is no simple mechanism to iterate over the values of the variadic template. Using the unpack operator however, 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 rvalue references (see above), this allows for perfect forwarding:
template<typename TypeToConstruct> struct SharedPtrAllocator
{
template<typename ...Args> std::shared_ptr<TypeToConstruct> ConstructWithSharedPtr(Args&&... params)
{
return std::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 std::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. These are 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. For example, R"delimiter[[a-z]]delimiter"
is equivalent to "[a-z]"
.[8]
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 are 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 integer and floating point raw literals is through a variadic template:
template<char...> OutputType operator "" _Suffix();
OutputType someVariable = 1234_Suffix;
OutputType anotherVariable = 2.17_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 numeric literals, the type of the cooked literal is either unsigned long long
for integral literals or long double
for floating point literals. (Note: There is no need for signed integral types because a sign-prefixed literal is parsed as expression containing the sign as unary prefix operator and the unsigned number.) There is no alternative template form:
OutputType operator "" _Suffix(unsigned long long);
OutputType operator "" _Suffix(long double);
OutputType someVariable = 1234_Suffix; // uses the first function
OutputType anotherVariable = 3.1416_Suffix; // uses the second function
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 standardize 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.
Explicitly-defaulted and deleted special member functions
In standard C++, the compiler will provide, for classes that do not provide for themselves, a default constructor, a copy constructor, a copy assignment operator (operator=), and a destructor. The user can override these defaults by defining their own versions. C++ also defines several global operators (such as operator= and operator new) that work on all classes, which the user can override.
However, there is very little control 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 is a violation of the one definition rule. While a diagnostic message is not required,[1] this typically results in a linker error.[citation needed]
In the case of the default constructor, the compiler will not generate a default constructor if a class is defined with any constructors. This is useful in many cases, but it is also useful to be able to have both specialized constructors and the compiler-generated default.
C++0x will allow the explicit defaulting and deleting of these special member 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;
};
An object of this type 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 most C++ compilers support it as an extension.[2][3] 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 operator 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:
- Rvalue references and the associated move support
- Support for the UTF-16 encoding unit, and UTF-32 encoding unit Unicode 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 and promises for passing asynchronous results between threads, and std::packaged_task
for wrapping up a function call that can generate such an asynchronous result. The futures proposal was criticized because it lacks a way to combine futures and check for the completion of one promise inside a set of promises[4].
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 | Associated values | Equivalent keys |
---|---|---|
unordered_set |
No | No |
unordered_multiset |
No | Yes |
unordered_map |
Yes | No |
unordered_multimap |
Yes | Yes |
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.
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
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 C++ 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.
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:
Class template | Integral/floating-point | Quality | Speed | Size of state |
---|---|---|---|---|
linear_congruential
|
Integral | Medium | Medium | 1 |
subtract_with_carry
|
Both | Medium | Fast | 25 |
mersenne_twister
|
Integral | Good | Fast | 624 |
C++0x will also provide a number of standard distributions: uniform_int_distribution
, bernoulli_distribution
, geometric_distribution
, poisson_distribution
, binomial_distribution
, uniform_real_distribution
, exponential_distribution
, normal_distribution
, and gamma_distribution
.
The generator and distributions are combined as in the following example:
std::uniform_int_distribution<int> distribution(0, 99);
std::mt19937 engine;
auto generator = std::bind(distribution, engine);
int random = generator(); // Generate a uniform integral variate between 0 and 99.
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 increment 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 characteristics 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.
Features planned but removed or not included
Heading for a separate TR:
- Modules
- Decimal Types
- Math Special Functions
Postponed:
- Concepts
- Garbage collection
- Reflection
- Macro Scopes
See also
- Technical Report 1
- C99, latest standard for the C programming language
References
- ↑ ISO/IEC (2003). ISO/IEC 14882:2003(E): Programming Languages - C++ §3.2 One definition rule [basic.def.odr] para. 3
- ↑ http://gcc.gnu.org/onlinedocs/gcc/Long-Long.html
- ↑ http://msdn.microsoft.com/en-us/library/s3f49ktz(VS.80).aspx
- ↑ Milewski, Bartosz (3 March 2009). "Broken promises–C++0x futures". http://bartoszmilewski.wordpress.com/2009/03/03/broken-promises-c0x-futures/. Retrieved 24 January 2010.
C++ Standards Committee papers
- ^ Doc No. 1401: Jan Kristoffersen (October 21, 2002) Atomic operations with multi-threaded environments
- ^ Doc No. 1402: Doug Gregor (October 22, 2002) A Proposal to add a Polymorphic Function Object Wrapper to the Standard Library
- ^ Doc No. 1403: Doug Gregor (November 8, 2002) Proposal for adding tuple types into the standard library
- ^ Doc No. 1424: John Maddock (March 3, 2003) A Proposal to add Type Traits to the Standard Library
- ^ Doc No. 1429: John Maddock (March 3, 2003) A Proposal to add Regular Expression to the Standard Library
- ^ Doc No. 1449: B. Stroustrup, G. Dos Reis, Mat Marcus, Walter E. Brown, Herb Sutter (April 7, 2003) Proposal to add template aliases to C++
- ^ Doc No. 1450: P. Dimov, B. Dawes, G. Colvin (March 27, 2003) A Proposal to Add General Purpose Smart Pointers to the Library Technical Report (Revision 1)
- ^ Doc No. 1452: Jens Maurer (April 10, 2003) A Proposal to Add an Extensible Random Number Facility to the Standard Library (Revision 2)
- ^ Doc No. 1453: D. Gregor, P. Dimov (April 9, 2003) A proposal to add a reference wrapper to the standard library (revision 1)
- ^ Doc No. 1454: Douglas Gregor, P. Dimov (April 9, 2003) A uniform method for computing function object return types (revision 1)
- ^ Doc No. 1456: Matthew Austern (April 9, 2003) A Proposal to Add Hash Tables to the Standard Library (revision 4)
- ^ Doc No. 1471: Daveed Vandevoorde (April 18, 2003) Reflective Metaprogramming in C++
- ^ Doc No. 1676: Bronek Kozicki (September 9, 2004) Non-member overloaded copy assignment operator
- ^ Doc No. 1704: Douglas Gregor, Jaakko Järvi, Gary Powell (September 10, 2004) Variadic Templates: Exploring the Design Space
- ^ Doc No. 1705: J. Järvi, B. Stroustrup, D. Gregor, J. Siek, G. Dos Reis (September 12, 2004) Decltype (and auto)
- ^ Doc No. 1717: Francis Glassborow, Lois Goldthwaite (November 5, 2004) explicit class and default definitions
- ^ Doc No. 1719: Herb Sutter, David E. Miller (October 21, 2004) Strongly Typed Enums (revision 1)
- ^ Doc No. 1720: R. Klarer, J. Maddock, B. Dawes, H. Hinnant (October 20, 2004) Proposal to Add Static Assertions to the Core Language (Revision 3)
- ^ Doc No. 1757: Daveed Vandevoorde (January 14, 2005) Right Angle Brackets (Revision 2)
- ^ Doc No. 1811: J. Stephen Adamczyk (April 29, 2005) Adding the long long type to C++ (Revision 3)
- ^ Doc No. 1815: Lawrence Crowl (May 2, 2005) ISO C++ Strategic Plan for Multithreading
- ^ Doc No. 1827: Chris Uzdavinis, Alisdair Meredith (August 29, 2005) An Explicit Override Syntax for C++
- ^ Doc No. 1834: Detlef Vollmann (June 24, 2005) A Pleading for Reasonable Parallel Processing Support in C++
- ^ Doc No. 1836: ISO/IEC DTR 19768 (June 24, 2005) Draft Technical Report on C++ Library Extensions
- ^ Doc No. 1886: Gabriel Dos Reis, Bjarne Stroustrup (October 20, 2005) Specifying C++ concepts
- ^ Doc No. 1891: Walter E. Brown (October 18, 2005) Progress toward Opaque Typedefs for C++0X
- ^ Doc No. 1898: Michel Michaud, Michael Wong (October 6, 2004) Forwarding and inherited constructors
- ^ Doc No. 1919: Bjarne Stroustrup, Gabriel Dos Reis (December 11, 2005) Initializer lists
- ^ Doc No. 1968: V Samko; J Willcock, J Järvi, D Gregor, A Lumsdaine (February 26, 2006) Lambda expressions and closures for C++
- ^ Doc No. 1986: Herb Sutter, Francis Glassborow (April 6, 2006) Delegating Constructors (revision 3)
- ^ Doc No. 2016: Hans Boehm, Nick Maclaren (April 21, 2002) Should volatile Acquire Atomicity and Thread Visibility Semantics?
- ^ Doc No. 2142: ISO/IEC DTR 19768 (January 12, 2007) State of C++ Evolution (between Portland and Oxford 2007 Meetings)
- ^ Doc No. 2228: ISO/IEC DTR 19768 (May 3, 2007) State of C++ Evolution (Oxford 2007 Meetings)
- ^ Doc No. 2258: G. Dos Reis and B. Stroustrup Templates Aliases
- ^ Doc No. 2280: Lawrence Crowl (May 2, 2007) Thread-Local Storage
- ^ Doc No. 2291: ISO/IEC DTR 19768 (June 25, 2007) State of C++ Evolution (Toronto 2007 Meetings)
- ^ Doc No. 2336: ISO/IEC DTR 19768 (July 29, 2007) State of C++ Evolution (Toronto 2007 Meetings)
- ^ Doc No. 2389: ISO/IEC DTR 19768 (August 7, 2007) State of C++ Evolution (pre-Kona 2007 Meetings)
- ^ Doc No. 2431: SC22/WG21/N2431 = J16/07-0301 (October 2, 2007), A name for the null pointer: nullptr
- ^ Doc No. 2432: ISO/IEC DTR 19768 (October 23, 2007) State of C++ Evolution (post-Kona 2007 Meeting)
- ^ Doc No. 2437: Lois Goldthwaite (October 5, 2007) Explicit Conversion Operators
- ^ Doc No. 2461: ISO/IEC DTR 19768 (October 22, 2007) Working Draft, Standard for programming Language C++
- ^ Doc No. 2507: ISO/IEC DTR 19768 (February 4, 2008) State of C++ Evolution (pre-Bellevue 2008 Meeting)
- ^ Doc No. 2544: Alan Talbot, Lois Goldthwaite, Lawrence Crowl, Jens Maurer (February 29, 2008) Unrestricted unions
- ^ Doc No. 2565: ISO/IEC DTR 19768 (March 7, 2008) State of C++ Evolution (post-Bellevue 2008 Meeting)
- ^ Doc No. 2597: ISO/IEC DTR 19768 (April 29, 2008) State of C++ Evolution (pre-Antipolis 2008 Meeting)
- ^ Doc No. 2606: ISO/IEC DTR 19768 (May 19, 2008) Working Draft, Standard for Programming Language C++
- ^ Doc No. 2697: ISO/IEC DTR 19768 (June 15, 2008) Minutes of WG21 Meeting June 8-15, 2008
- ^ Doc No. 2798: ISO/IEC DTR 19768 (October 4, 2008) Working Draft, Standard for Programming Language C++
- ^ Doc No. 2857: ISO/IEC DTR 19768 (March 23, 2009) Working Draft, Standard for Programming Language C++
- ^ Doc No. 2869: ISO/IEC DTR 19768 (April 28, 2009) State of C++ Evolution (post-San Francisco 2008 Meeting)
- ^ Doc No. 3000: ISO/ISC DTR 19769 (November 9, 2009) Working Draft, Standard for Programming Language C++
- ^ Doc No. 3014: Stephen D. Clamage (November 4, 2009) AGENDA, PL22.16 Meeting No. 53, WG21 Meeting No. 48, March 8-13, 2010, Pittsburgh, PA
Articles
- ^ Bjarne Stroustrup (January 2, 2006). "A Brief Look at C++0x". The C++ Source. http://www.artima.com/cppsource/cpp0x.html. Retrieved 2009-03-23.
- ^ Bjarne Stroustrup (May 1, 2005). "The Design of C++0x: Reinforcing C++’s proven strengths, while moving into the future". C/C++ Users Journal. http://www.research.att.com/~bs/rules.pdf. Retrieved 2009-03-23.
- ^ Raffaele Rialdi (September 16, 2005). "Il futuro di C++ raccontato da Herb Sutter". Web Log di Raffaele Rialdi. http://blogs.ugidotnet.org/raffaele/archive/2005/09/16/26570.aspx. Retrieved 2009-03-23.
- ^ Danny Kalev (July 21, 2006). "The Explicit Conversion Operators Proposal". InformIT. http://www.informit.com/guides/content.aspx?g=cplusplus&seqNum=297. Retrieved 2009-03-23.
- ^ Danny Kalev (July 11, 2008). "Lambda Expressions and Closures". InformIT. http://www.informit.com/guides/content.aspx?g=cplusplus&seqNum=254. Retrieved 2009-03-23.
- ^ Pete Becker (April 11, 2006). "Regular Expressions". Dr. Dobb's Portal. http://www.ddj.com/cpp/185300414. Retrieved 2009-03-23.
- ^ Danny Kalev (March 10, 2006). "The Type Traits Library". InformIT. http://www.informit.com/guides/content.aspx?g=cplusplus&seqNum=276. Retrieved 2009-03-23.
- ^ Pete Becker (May 1, 2005). "C++ Function Objects in TR: Getting from TR1 back to the Standard Library". Dr. Dobb's Portal. http://www.ddj.com/cpp/184401949. Retrieved 2009-03-23.
- ^ Howard E. Hinnant, Bjarne Stroustrup, and Bronek Kozicki (March 10, 2008). "A Brief Introduction to Rvalue References". The C++ Source. http://www.artima.com/cppsource/rvalue.html. Retrieved 2009-03-23.
- ^ "C++0x: The Dawning of a New Standard". DevX. August 18, 2008. http://www.devx.com/SpecialReports/Door/38865. Retrieved 2009-03-23.
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, 9 November, 2009
- Wiki page to help keep track of C++ 0x core language features and their availability in compilers
- C++0x - the next ISO C++ standard, C++0x FAQ maintained by Bjarne Stroustrup
es:C++0x fr:C++1x ko:C++0x it:C++0x ja:C++0x pl:C++0x pt:C++0x ru:C++0x sv:C++#Historia th:C++0x zh:C++0x
If you like SEOmastering Site, you can support it by - BTC: bc1qppjcl3c2cyjazy6lepmrv3fh6ke9mxs7zpfky0 , TRC20 and more...