C++0X features

Auto

template<class T> void printall(const vector<T>& v)
{
  for (typename vector<T>::const_iterator p = v.begin(); p!=v.end(); ++p)
     cout << *p << "\n";
}

template<class T> void printall(const vector<T>& v)
{
  for (auto p = v.begin(); p!=v.end(); ++p)
     cout << *p << "\n";
}


When the type of a variable depends critically on template argument it can
be really hard to write code without auto. For example:

template<class T, class U> void (const vector<T>& vt, const vector<U>& vu)
{
  // ...
  auto tmp = vt[i]*vu[i];
  // ...
}


Range for

A range for statement allows you to iterate through a "range",
which is anything you can iterate through like an STL-sequence
defined by a begin() and end(). All standard containers can be
used as a range, as can a std::string, an initializer list, an
array, and anything for which you define begin() and end(), e.g.
an istream. For example:

void f(const vector<double>& v)
{
  for (auto x : v) cout << x << '\n';
  for (auto& x : v) ++x;  // using a reference to allow us to chage the value
}

You can read that as "for all x in v" going through starting with
v.begin() and iterating to v.end(). Another example:

for (const auto x : { 1,2,3,5,8,13,21,34 }) cout << x << '\n';

The begin() (and end()) can be a member to be called x.begin()
or a free-standing function to be called begin(x).


Default and delete functions

class X
{
  // ...
  X& operator=(const X&) = delete;      // Disallow copying
  X(const X&) = delete;
};

Conversely, we can also say explicitly that we want to default 
copy behavior:

class Y
{
  // ...
  Y& operator=(const Y&) = default;     // default copy semantics
  Y(const Y&) = default;
};


Enum class

enum Alert { green, yellow, election, red }; // traditional enum

enum class Color { red, blue };   // scoped and strongly typed enum
                                  // no export of enumerator names into enclosing scope
                                  // no implicit conversion to int
enum class TrafficLight { red, yellow, green };

  Alert a = 7;              // error (as ever in C++)
  Color c = 7;              // error: no int->Color conversion
  int a2 = red;             // ok: Alert->int conversion
  int a3 = Alert::red;      // error in C++98; ok in C++0x
  int a4 = blue;            // error: blue not in scope
  int a5 = Color::blue;     // error: not Color->int conversion  
  Color a6 = Color::blue;   // ok

  enum class Color : char { red, blue };        // compact representation

  enum class TrafficLight { red, yellow, green };  // by default, the underlying type is int

  enum E { E1 = 1, E2 = 2, Ebig = 0xFFFFFFF0U };   // how big is an E?
                                                         // (whatever the old rules say;
                                                         // i.e. "implementation defined")

  enum EE : unsigned long { EE1 = 1, EE2 = 2, EEbig = 0xFFFFFFF0U };   // now we can be specific
It also enables forward declaration of enums:

  enum class Color_code : char;     // (forward) declaration
  void foobar(Color_code* p);       // use of forward declaration
        // ...
  enum class Color_code : char { red, yellow, green, blue }; // definition
  

Constexpr

        enum Flags { good=0, fail=1, bad=2, eof=4 };

        constexpr int operator|(Flags f1, Flags f2) { return Flags(int(f1)|int(f2)); }

        void f(Flags x)
        {
                switch (x) {
                case bad:         /* ... */ break;
                case eof:         /* ... */ break;
                case bad|eof:     /* ... */ break;
                default:          /* ... */ break;
                }
        }


Decltype

decltype -- the type of an expression
decltype(E) is the type ("declared type") of the name or expression E
and can be used in declarations. For example:

        void f(const vector<int>& a, vector<float>& b)
        {
                typedef decltype(a[0]*b[0]) Tmp;
                for (int i=0; i<b.size(); ++i) {
                        Tmp* p = new Tmp(a[i]*b[i]);
                        // ...
                }
                // ...
        }


Initializer list

        vector<double> v = { 1, 2, 3.456, 99.99 };
        list<pair<string,string>> languages = {
                {"Nygaard","Simula"}, {"Richards","BCPL"}, {"Ritchie","C"}
        };
        map<vector<string>,vector<int>> years = {
                { {"Maurice","Vincent", "Wilkes"},{1913, 1945, 1951, 1967, 2000} },
                { {"Martin", "Ritchards"} {1982, 2003, 2007} },
                { {"David", "John", "Wheeler"}, {1927, 1947, 1951, 2004} }
        };


Delegating constructors

In C++98, if you want two constructors to do the same thing, repeat yourself or call "an init() function." For example:

        class X {
                int a;
                validate(int x) { if (0<x && x<=max) a=x; else throw bad_X(x); }
        public:
                X(int x) { validate(x); }
                X() { validate(42); }
                X(string s) { int x = lexical_cast<int>(s); validate(x); }
                // ...
        };

Verbosity hinders readability and repetition is error-prone. Both get in the way of maintainability. So, in C++0x, we can define one constructor in terms of another:

        class X {
                int a;
        public:
                X(int x) { if (0<x && x<=max) a=x; else throw bad_X(x); }
                X() :X{42} { }
                X(string s) :X{lexical_cast<int>(s)} { }
                // ...
        };


Use constructors

        class Derived : public Base {
        public
                using Base::f;    // lift Base's f into Derived's scope -- works in C++98
                void f(char);     // provide a new f
                void f(int);      // prefer this f to Base::f(int)

                using Base::Base; // lift Base constructors Derived's scope -- C++0x only
                Derived(char);    // provide a new constructor
                Derived(int);     // prefer this constructor to Base::Base(int)
                // ...
        };


Static assert


int f(int* p, int n)
{
  static_assert(p==0,"p is not null");  // error: static_assert() expression not a constant expression
                // ...
}


Nullptr
 
  char* p = nullptr;
 
  void f(int);
  void f(char*);

  f(0);         // call f(int)
  f(nullptr);   // call f(char*)



Variadic templates

template<class ... Types>
void f(Types ... args); // variadic template function
                                        // (i.e. a function that can take an arbitrary number of arguments of arbitrary types)
        f();            // OK: args contains no arguments
        f(1);          // OK: args contains one argument: int
        f(2, 1.0);     // OK: args contains two arguments: int and double



Rvalue reference

template<class T> class vector {
  // ...
  vector(const vector&);                        // copy constructor
  vector(vector&&);                     // move constructor
  vector& operator=(const vector&);     // copy assignment
  vector& operator=(vector&&);          // move assignment
};      // note: move constructor and move assignment takes non-const &&
        // they can, and usually do, write to their argument

The && indicates an "rvalue reference". An rvalue reference can bind to
an rvalue (but not to an lvalue):

        X a;
        X f();
        X& r1 = a;              // bind r1 to a (an lvalue)
        X& r2 = f();            // error: f() is an rvalue; can't bind

        X&& rr1 = f();  // fine: bind rr1 to temporary
        X&& rr2 = a;    // error: bind a is an lvalue

        template<class T>
        void swap(T& a, T& b)  // "perfect swap" (almost)
        {
                T tmp = move(a);        // could invalidate a
                a = move(b);            // could invalidate b
                b = move(tmp);          // could invalidate tmp
        }


User defined literals


constexpr complex<double> operator "" i(long double d)  // imaginary literal
{
  return {0,d}; // complex is a literal type
}


Lambda

        vector<int> v = {50, -10, 20, -30};

        std::sort(v.begin(), v.end());  // the default sort
        // now v should be { -30, -10, 20, 50 }

        // sort by absolute value:
        std::sort(v.begin(), v.end(), [](int a, int b) { return abs(a)<abs(b); });
        // now v should be { -10, 20, -30, 50 }


A lambda expression can access local variables in the scope in
which it is used. For example:

        void f(vector<Record>& v)
        {
                vector<int> indices(v.size());
                int count = 0;
                fill(indices.begin(),indices.end(),[&count](){ return ++count; });

                // sort indices in the order determined by the name field of the records:
                std::sort(indices.begin(), indices.end(), [&](int a, int b) { return v[a].name<v[b].name; });
                // ...
        }


Threads

        #include<thread>

        void f();

        struct F {
                void operator()();
        };

        int main()
        {
                std::thread t1{f};      // f() executes in separate thread
                std::thread t2{F()};    // F()() executes in separate thread
        }
 

        int main()
        {
                std::thread t1{f};      // f() executes in separate thread
                std::thread t2{F()};    // F()() executes in separate thread

                t1.join();      // wait for t1
                t2.join();      // wait for t2
        }