Mead's Guide to Modern C++
(An Introduction)

Last update: July 14, 2022 at 11:50:28


List of topics (in no real order):

  1. Overview
  2. Right Angle Brackets (N1757)
  3. Deprecated register keyword (P0001R1)
  4. Binary Literals (N3472)
  5. Single-Quote As a Digit Separator (N3781)
  6. Explicit Conversion Operators
  7. Uniform Initialization
  8. Initializer Lists (N2672)
  9. Range-Based For Loops (N2930)
  10. nullptr (N2431)
  11. Strongly Typed Enums (N2347)
  12. auto Deductions (N1984)
  13. Forward Declarations Of Enums (N2764)
  14. Raw and Unicode String Literals (N2442)
  15. Non-static Data Member Initializers (N2756)
  1. Trailing Return Types (N3276)
  2. __func__ Predefined Identifier (N2340)
  3. Delegating Constructors (N1986)
  4. noexcept
  5. Generalized constexpr (N2235)
  6. Template Aliases (N2258)
  7. Lambdas (N2927)
  8. Long Long data type (N1811)
  9. Defaulted and Deleted functions (N2346)
  10. Structured Bindings (P0144R2)
  11. Generalized Attributes (N2761)
  12. Stricter Expression Evaluation Order (P0145R3)
  13. std::array
  14. References

Overview

Because there were so many additions and changes to the C++ language and the libraries, it is virtually impossible to cover everything in one document. (Short of the 1500+ pages of the standard.) This document is just going to give you an introduction to many of these enhancements. Some explanations will be fairly short, and others will be longer. If you really want to know everything about everything, there are links to additional information on each topic. Be warned, though, that some of the documents are quite lengthy and complex and require quite a bit of C++ programming experience.

The topics presented should be understandable by anyone that has programmed in C++ for a few months. I am not going to cover topics that I consider more "advanced" such as move semantics, rvalue references, universal references, perfect forwarding, deduction guides, fold expressions, variadic templates, or template type deduction vs. auto type deduction. I consider the topics covered here to be used by Everyday C++ Programmers™. I'm also not covering the additions to the STL (e.g. concurrency, regular expressions, smart pointers).

I present the topics in no particular order. However, some may need to be looked at before others, as they may have some dependencies.

To build these examples, you may need to tell the compiler which "standard" to use. Most of the examples only require a C++11-compliant compiler, but some of them use features from a later standard, (e.g. C++14, C++17, C++20, etc.) To specify the version with g++ and clang++, use the -std=XXX compiler option where XXX is the version. For Microsoft's compiler, cl, use /std:XXX. Examples:

g++ -std=c++11 foo.cpp
clang++ -std=c++14 foo.cpp
g++ -std=c++17 foo.cpp
cl /std:c++17 foo.cpp

This is the list of included files to compile all of the examples:

#include <algorithm>
#include <array>
#include <bitset>
#include <cmath>
#include <deque>
#include <initializer_list>
#include <iostream>
#include <list>
#include <set>
#include <string>
#include <tuple>
#include <typeinfo>
#include <vector>
Also, you must have this at the top of the file to make the examples compile:
using namespace std;
Finally, if you're really interested in learning this stuff, you must actually use it. Reading about the new features is all fine and good, but you're not going to get proficient by simply reading about them. Remember one of Mead's mottos: "Programming is not a spectator sport."

All of the code examples should compile and run (unless they are purposely showing improper use), so you can copy and paste them into your sandbox and play with them to answer all of your questions like "Can I do this?" and "What happens if I do that?"

But hey, enough of my yakkin'; whaddaya say? Let's boogie!

Right Angle Brackets (N1757)

This is probably the lowest of the low-hanging fruit to be picked! Consider the problem:
vector<list<int>> vl;  // Error in C++03 because >> is the right shift operator!
vector<list<int> > vl; // This was the "fix" in C++03
For years, C++ programmers have been typing that "work-around". Now, they don't have to.

Error from g++:

 error: spurious '>>', use '>' to terminate a template argument list
   std::vector<std::list>> vl;
Error from Clang:
error: a space is required between consecutive right angle brackets (use '> >')
  std::vector<std::list>> vl;
                       ^~
                       > >
That's about it for this one, but if you want to read more about the history, go here.

Deprecated register keyword (P0001R1)

This is (another) attempt to reclaim an existing keyword (much like the auto keyword). For years, the register keyword has only been a hint or suggestion to the compiler, and most compilers ignore it. A C++11 compliant compiler might emit a warning for this code:
register int i = 10; // deprecated in C++11
The warning from clang (using -std=c++11):
warning: 'register' storage class specifier is deprecated and incompatible with C++17 [-Wdeprecated-register]
  register int i = 10;
  ^~~~~~~~~
1 warning generated.
Now, in C++17, the keyword has been removed and the code above generates an error. Compiling with clang and -std=c++17:
error: ISO C++17 does not allow 'register' storage class specifier [-Wregister]
  register int i = 10;
  ^~~~~~~~~
1 error generated.
Note that, in C++17, the keyword has been removed, but you can't use it for an identifier because it is still reserved for future use:
int register = 10; // use register as a variable name
Error message from clang and -std=c++17:
error: expected unqualified-id
  int register = 10;
               ^
This should not present a problem for most newer code, since programmers have been warned for years about the register keyword being ignored. I generally only see new programmers use it because it gives them a false sense that their code will somehow run faster by using the keyword. Compilers are much smarter than programmers when it comes to optimizing the source code.

I wrote a discussion about some of the storage classes in C here.

Binary Literals (N3472)

This feature may seem very insignificant, and may well be. But, if you find yourself doing a lot of bit-twiddling, this is a great addition to the language. We always had the ability to write integral literals as decimal, octal, and hexadecimal. Now, we have binary:
  // All values are equivalent, decimal 17
int i1 = 17;      // decimal
int i2 = 021;     // octal (leading zero)
int i3 = 0x11;    // hexadecimal (leading 0x or OX)
int i4 = 0b10001; // C++14 binary (leading Ob or OB)

  // All lines output 17 (decimal)
cout << "i1 is " << i1 << endl;
cout << "i2 is " << i2 << endl;
cout << "i3 is " << i3 << endl;
cout << "i4 is " << i4 << endl;

  // Overriding the default decimal base
cout << oct << showbase << i1 << endl; // 021
cout << hex << showbase << i1 << endl; // 0x11

  // Unfortunately, there currently is no built-in way to print in binary
cout << bin << showbase << i1 << endl; // The bin manipulator doesn't exist!!
For now, you'll have to resort to some other way to get std::ostream to display values in binary.

For an easy way to print an integer in binary, you can use a std::bitset. This is a templated class that takes a non-type (value) template parameter that represents the number of bits. The class overloads operator<< to display the ones and zeros:

cout << bitset<5>(i1) << endl;  // output: 10001
cout << bitset<8>(i1) << endl;  // output: 00010001
cout << bitset<16>(i1) << endl; // output: 0000000000010001
cout << bitset<32>(i1) << endl; // output: 00000000000000000000000000010001
cout << bitset<47>(i1) << endl; // output: 00000000000000000000000000000000000000000010001
You need to include the proper header file:
#include <bitset>

Single-Quote As a Digit Separator (N3781)

Quick, what's the value of a below?
long long a = 10000000000; // Hold on, let me count the zeros...
Ok, what's the value of b below?
long long b = 10,000,000,000; // Easy! 10 billion
Those little marks (commas) make it trivially easy to know the exact value of the data. Unfortunately, the comma is already used as an operator so we can't use it here. But, we can use the single-quote character:
long long b = 10'000'000'000; // Still easy to read
The single-quotes are just for humans (programmers). The compiler strips them out. This means that the groupings and positions are somewhat arbitrary. These all mean the exact same thing:
long long b;
b = 10000000000; 
b = 10'000'000'000; 
b = 100'0000'0000;
b = 1'0000'000000;
b = 100'00'00'00'00;
b = 1'0'0'0'0'0'0'0'0'0'0;
One reason for the arbitrary nature of the groupings is that each culture has its own way of grouping numbers. Also, cultures may use different symbols for delimiting the groups. Some cultures use a comma, or a dot, or a space. The C++ culture chose to use the single quotation character.

This delimiter will work with any number base:

int i1 = 1'234'789;   // decimal
int i2 = 01'234'567;  // octal
int i3 = 0x1'abc'def; // hexadecimal
int i4 = 0b1'000'101; // binary
as well as with floating-point types:
float f = 3.14'999'999F;          // float
double d1 = 1'234.7'200'009;      // double
double d2 = 1.234'567e+123;       // double (e-notation)
double d3 = 1.2'3'4'5'6'7e+1'2'3; // crazy!!
Notes:

Explict Conversion Operators (N2437)

First, a quick review of conversion constructors.

C++ has had conversion constructors forever. A conversion constructor is essentially a one-argument constructor. This constructor, then, converts the argument into an object of the class' type. Hence, the term, conversion constructor. Quick example:

class Foo3
{
  public:
    // Conversion constructor
    Foo3(int x) : x_(x)
    {
    }
  private:
    int x_;
};
With the conversion constructor available, the compiler with automatically and silently convert an integer to a Foo3 object whenever it is necessary:
void fn1(const Foo3& f)
{
  // Do something with f
}

Foo3 f(42); // Construct a Foo3 object from an integer (conversion constructor)
f = 43;     // The conversion constructor is called implicitly
fn1(45);    // The conversion constructor is called implicitly
In the code above, the assignment operator expects a Foo3 object, but the programmer has given it an integer. The compiler makes a call to the conversion constructor to perform the conversion before it is passed to the assignment operator. A similar thing occurs when calling function fn1 with an integer when it expects a Foo3 object.

To prevent these automatic and silent conversions, you simply mark the conversion constructor as explicit:

// Explicit conversion constructor
explicit Foo3(int x) : x_(x)
{
}
Now the code above will emit these errors:
error: no viable overloaded '='
  f = 43;     // The conversion constructor is called implicitly
  ~ ^ ~~
note: candidate function (the implicit copy assignment operator) not viable: no known conversion from 'int' to 'const Foo3' for 1st argument
class Foo3
      ^
error: no matching function for call to 'fn1'
  fn1(43);    // The conversion constructor is called implicitly
  ^~~
note: candidate function not viable: no known conversion from 'int' to 'const Foo3' for 1st argument
void fn1(const Foo3& f)
     ^
2 errors generated.
Marking the conversion constructor explicit means that the programmer must explicitly cast the integers:
f = Foo3(43);  // OK, explicit cast
fn1(Foo3(43)); // OK, explicit cast
Conversion constructors are used to convert some other type (e.g. int) into the object's type (e.g. Foo3). What if we want to go in the other direction: converting the object's type into some other type?
Foo3 f(42); // Construct a Foo3 object from an integer

int i = f;                   // Error: Can't assign a Foo3 to an integer
int j = (int)f;              // Error: Still can't do it (compiler doesn't know how)
int k = int(f);              // Nope
int n = static_cast<int>(f); // Nope
That's where conversion operators come in. They tell the compiler how to convert (cast) the object into some other type.

Adding a conversion operator to the Foo3 class:

class Foo3
{
  public:
    // Conversion constructor
    explicit Foo3(int x) : x_(x)
    {
    }

    // Conversion operator
    operator int() const
    {
      return x_;
    }

  private:
    int x_;
};
Now the above conversions to integer work as expected. C++11 has added the ability to mark these conversion operators as explicit, much like conversion constructors:
// Conversion operator
explicit operator int() const
{
  return x_;
}
This will once again fail:
int i = f; // Error: Can't implicitly convert a Foo3 to integer
However, these will all work fine:
int j = (int)f;              // OK, explicit C-style cast
int k = int(f);              // OK, explicit C++-style cast
int n = static_cast<int>(f); // OK, explicit C++ named cast
You can convert to any type, as long as you provide the appropriate conversion operator. This function expects a string:
void prints(const string& str)
{
  cout << str << endl;
}

Foo3 f(42); // Construct a Foo3 object from an integer
prints(f);  // Error: No conversion from Foo3 to string
Add another conversion operator to Foo3:
// You can mark this explicit, if necessary
operator std::string() const
{
  return std::to_string(x_); // to_string is new in C++11
}
Foo3 f(42); // Construct a Foo3 object from an integer
prints(f);  // OK, now prints 42
Notes: See more at Stroustup's FAQ regarding explicit conversion operators.

Uniform Initialization (uniform-init a.k.a. Brace Initialization)

This is actually part of Initializer Lists (N2672) described below, but I wanted to demonstrate the simplest uses before the more complicated ones.

Initializing data in C++ is pretty straight-forward, and there are only a few rules that you have to remember.
  1. Simple built-in scalar types:
    int a = 1; // Copy initialization ("assignment" operator)
    int b(3);  // Direct initialization (parentheses)
    
  2. Arrays:
      // Use "assignment" operator and braces to initialize the arrays
    int array1[] = {1, 2, 3};                       
    const char *array2[] = {"one", "two", "three"};
    
  3. Structs (POD types):
    struct Point
    {
      double x;
      double y;
    };
    
      // Use "assignment" operator and braces to initialize the struct
    Point p = {1.0, 2.0};
    
  4. Classes or structs (with private members)
    class Foo
    {
      public: 
        Foo(int v1, int v2) : a_(v1) // This is initialization (member initializer list)
        {
          b_ = v2; // This is assignment
        }
      private:
        int a_;
        int b_;
    };
    
    Foo f(1, 2); // a_ will be initialized by the constructor
    
These ways of initialization have worked fairly well for years, but they are inconsistent. Also, there are things that still cannot be initialized (e.g. arrays that are members of a class). Well, now things have changed. C++11 adds yet-another way to initialize things:
  // Simple initialization
double d1 = 3.14;   // C++98 (copy initialization)
double d2 = {3.14}; // C++98 (brace initialization, was almost never used)
double d3(3.14);    // C++98 (direct initialization)
double d4{3.14};    // C++11 (brace initialization)
This means that you can be consistent and use braces for all of your initializations. Using braces causes the compiler to ensure no loss of data (which is expected):
int i1 = 3.14;   // Clang warns, g++ is silent (even with -Wall, need -Wconversion)
int i2(3.14);    // Clang warns, g++ is silent (even with -Wall, need -Wconversion)
int i3{3.14};    // Clang error, g++ error
int i4 = {3.14}; // Clang error, g++ error (new behavior)
However, you might be surprised by this:
int i5 = 1;    // OK
double d5 = 2; // OK
double d6{1};  // OK, literal is known at compile-time
double d7{i5}; // Clang error, g++ warning,
int i6{d5};    // Clang error, g++ warning,
Setting data to the "default" value:
int ii1;         // Undefined (assume local inside of a function)
int ii2();       // Function prototype! a.k.a "the most vexing parse" (Clang warns)
int ii3{};       // 0 (New)
int ii4 = {};    // 0
int ii5 = int(); // 0
int ii6 = int{}; // 0 (New)
Ok, so which one should you use? All things being equal, I will defer to the man himself (Bjarne Stroustrup):

"Prefer the {}-initializer syntax for declarations with a named type."

There are times when you will use one of the other forms, but those are more advanced situations.

There is a nice consequence of this new syntax. It's called aggregate initialization and it allows you to initialize an aggregate data structure (array or POD structure) using default initialization.

Recall that we could always do this:

struct Point
{
  double x;
  double y;
};

Point p = {1.0, 2.0}; // Use "assignment" operator and braces to initialize the struct
Now, we can drop the "assignment" operator like this:
Point p {1.0, 2.0}; // Use braces to initialize the struct
We can now take it one step further and default-initialize all of the members with empty braces:
Point p {}; // x and y are both 0.0
Realize, however, if we just do this (without the braces)
Point p; // x and y are both undefined
the values of x and y are left undefined (as before).

The aggregate data type must either be an array or a class, struct, union that meets these criteria:

We typically call these data structures POD (Plain Old Data) structures because they generally contain only data. Here's another simple example:
struct S1
{
  public: 
    void print()
    {
      cout << "s is " << s << ", i is " << i << ", d is " << d << endl;      
    }
      // All are public
    string s;
    int i;
    double d;
};

S1 s1;                  // Undefined values for built-in types int and double (string is initialized to "")
S1 s2 = {"", 10, 3.14}; // Initialize all members (public)
S1 s3 = {};             // All members default-initialized {"", 0, 0.0}
S1 s4 {"", 10, 3.14};   // (C++11) Using uniform-initialization
S1 s5 {};               // (C++11) Using uniform-initialization {"", 0, 0.0}

s1.print(); // s is , i is 166494208, d is 3.11218e-317
s2.print(); // s is , i is 10, d is 3.14
s3.print(); // s is , i is 0, d is 0
s4.print(); // s is , i is 10, d is 3.14
s5.print(); // s is , i is 0, d is 0
Now, make the data members private:
struct S2
{
  public:
    void print()
    {
      cout << "s is " << s << ", i is " << i << ", d is " << d << endl;      
    }
  private:
    string s;
    int i;
    double d;
};

S2 s6;      // Undefined values for built-in types int and double
S2 s8 = {}; // All members default-initialized {"", 0, 0.0}
S2 s10 {};  // (C++11) all members default-initialized {"", 0, 0.0}

S2 s11 = {"", 10, 3.14}; // This is still illegal (private)

s6.print();  // s is , i is 166494208, d is 3.11218e-317
s8.print();  // s is , i is 0, d is 0
s10.print(); // s is , i is 0, d is 0

Technically, S2 is not a POD because it has private data. However, now using uniform-initialization, you can default-initialize them without a constructor. This may seem like a small advantage, and it probably is. The one other thing that is potentially more useful is that, since C++17, PODs can inherit from certain base classes (not shown here). This was not possible before C++11.

Links:

Initializer Lists (N2672)

Initializer lists are one of the most important new features (IMHO) in C++. They are somewhat related to the uniform intialization, but they have some caveats. Let's start simple with something that has been missing from C++ since the beginning: Member array initialization.

Member Array Initialization

This is how we would "initialize" an array previously:
class Foo2
{
  public:
    Foo2()
    {
        // C++98/03 can't initialize a member array. Must use a loop and "assign" values.
      for (int i = 0; i < 3; i++)
        array_[i] = i + 1;
    }
  private:
    int array_[3]; // How to initialize?
};
Now, C++11 adds the ability to initialize a member array using the member initializer list and braces:
class Foo2
{
  public:
    Foo2() : array_{1, 2, 3} // member array initialization (MUST use braces)
    {
      // empty body
    }
  private:
    int array_[3];
};
Be sure not to include parentheses in the member initializer list:
Foo2() : array_( {1, 2, 3} ) // Incorrect
C++11 also allows you to initialize the array directly in the class:
class Foo2
{
  public:
    Foo2()
    {
      // empty body
    }
  private:
    int array_[3] = {1, 2, 3}; // member array initialization (equal sign is optional)
};
You must still specify the size, even though there is an initializer list. This is the error from Clang without it:
error: array bound cannot be deduced from an in-class initializer
    int array_[] = {1, 2, 3}; // member array initialization (equal sign is optional)
                 ^
This is what GNU g++ says:
error: too many initializers for 'int [0]'
     int array_[] = {1, 2, 3}; // member array initialization (equal sign is optional)
                            ^
Another welcome addition is the ability to initialize a standard container with this syntax. Previously, like arrays, there was no easy way of initializing a vector. You had to do something like this:
  // size and capacity is 0
vector<int> v0;

  // Add elements
v0.push_back(1);
v0.push_back(2);
v0.push_back(3);
v0.push_back(4);
v0.push_back(5);

  // Size is 5, capacity is implementation-dependent (it's 8 with clang)
cout << "size: " << v0.size() << ", capacity: " << v0.capacity() << endl;

  // Initialize vector with initializer list syntax
vector<int> v1{1, 2, 3, 4, 5};

  // Size and capacity are both 5
cout << "size: " << v1.size() << ", capacity: " << v1.capacity() << endl;
Lists and other containers also work:
list<int> list1 {5, 4, 3, 2, 1};
deque<int> deque1 {3, 4, 5, 1, 2};
set<int> set1 {5, 4, 3, 2, 1};
Iterating over the containers to display the contents of the list, set, and deque, respectively:
5  4  3  2  1  
3  4  5  1  2  
1  2  3  4  5  


Functions taking initializer lists

A couple of functions to use:

// Function taking a vector
void fn1(const std::vector<int>& v)
{
  cout << "vector: ";
  print5(v);
}

// Function taking an initializer_list
void fn2(const std::initializer_list<int>& lst)
{
  cout << "init list: ";
  print5(lst);
}
Calling the functions:
fn1({1, 2, 3});               // conversion constructor for vector
fn1(vector<int>{1, 2, 3, 4}); // pass vector (temporary)
fn2({1, 2, 3, 4, 5});         // pass initializer_list
fn1(1, 2, 3, 4, 5);           // Error
fn2(1, 2, 3, 4, 5);           // Error
Output:
vector: 1  2  3  
vector: 1  2  3  4  
init list: 1  2  3  4  5  
Errors from Clang:
cpp14.cpp:357:3: error: no matching function for call to 'fn1'
  fn1(1, 2, 3);
  ^~~
cpp14.cpp:244:6: note: candidate function not viable: requires single argument 'v', 
                 but 3 arguments were provided
void fn1(const std::vector& v)
     ^
cpp14.cpp:358:3: error: no matching function for call to 'fn2'
  fn2(1, 2, 3);
  ^~~
cpp14.cpp:250:6: note: candidate function not viable: requires single argument 'lst', 
                       but 3 arguments were provided
void fn2(const std::initializer_list& lst)
     ^
Notes:


How would we add support for initializer lists to, say, our own Vector class?

  1. First, we would have to include the header file that supports initializer lists (in Vector.h):
    #include <initializer_list>
    
  2. And then add a new constructor to the header file:
    Vector(const std::initializer_list<int>& list);
    
  3. Then in the .cpp file we would implement it:
    Vector::Vector(const std::initializer_list<int>& list) 
       : array_(0), size_(0), capacity_(0)
    {
        // Get the number of elements in the intializer list
      size_t size = list.size();
    
        // The initializer list could be empty
      if (size)
      {
          // Just grow the internal array once (optimization)
        grow(size);
    
          // Iterate over the initializer list, pushing each element to the back
        std::initializer_list<int>::const_iterator it = list.begin();
        while (it != list.end())
          push_back(*it++);
      }
    }
    
  4. And then test it out with some driver code:
    Vector v {1, 2, 3, 4, 5};
    Print(v);
    
    Output:
    1  2  3  4  5  (size=5, capacity=5, allocs=1)
    

Links:

Range-Based For Loops (N2930)

Range-based for loops are another welcomed addition. They work a lot like similar constructs in other languages. However, they are not to be confused with the for_each generic algorithm:
template<typename InputIt, typename Op> Op for_each(InputIt first, InputIt last, Op op);
Examples will clarify. This is how we've used for loops with arrays since the beginning:
  // Initialize int array (20 bytes)
int a[] = {1, 2, 3, 4, 5};

  // Print out each element: 1 2 3 4 5
int size = sizeof(a) / sizeof(*a);
for (int i = 0; i < size; i++)
  cout << a[i] << " ";
cout << endl;
Now, with range-based for loops:
  // Using a range-based for: 1 2 3 4 5
for (int i : a)
  cout << i << " ";
cout << endl;
If we want to modify each element of the array, we need to use references:
  // Multiply each element by 10 (reference)
for (int& i : a)
  i *= 10;

  // Display: 10 20 30 40 50
for (int i : a)
  cout << i << " ";
cout << endl;
You can also use const with the references:
  // Assume some array of large objects
const BigObject BigObjectArray[] = {. . .};

  // Don't want to copy large objects, but don't want to modify either
for (const BigObject& b : BigObjectArray)
  ProcessBigObject(b);

Although I'm showing you how to use the range-based for with static arrays (for simplicity now), you will probably rarely do this because of the limitations of static arrays. Range-based for was primarily developed for containers (specifically STL containers). Also, static arrays are now used rarely because of the far superior std::array container (see below) that has been added to the STL.

Of course, as you'd expect, the standard containers work equally well. Using a std::list here, just to mix it up a bit. The first loop example is how it was done before C++11:
list<int> lst {1, 2, 3, 4, 5}; // Using C++11 initializer lists

  // Using C++98/03 iterators with for loop: 1 2 3 4 5
for (list<int>::iterator it = lst.begin(); it != lst.end(); ++it)
  cout << *it << " ";
cout << endl;
You can use the newly re-purposed auto keyword for the iterator. The compiler knows the type that lst.begin() returns, so it can deduce the type for it:
  // Using auto with iterators and for loop: 1 2 3 4 5
for (auto it = lst.begin(); it != lst.end(); ++it)
  cout << *it << " ";
cout << endl;
Using the new range-based for loops, the loop is made even more compact:
  // Using range-based for loop: 1 2 3 4 5
for (int i : lst)
  cout << i << " ";
cout << endl;
Here is another situation where this technique really shines.

Suppose we had a vector that already had values in it and we wanted to add a few more "random-like" values. This is how we might do it before:

  // Create a vector with some integers
vector<int> v {1, 2, 3, 4};

  // Do a bunch of stuff with the vector...

  // OLD WAY: Add some "random values" (verbose)
v.push_back(7);
v.push_back(11);
v.push_back(18);
v.push_back(-5);
v.push_back(0);
v.push_back(42);
Now, we can do the same thing in a more concise way:
  // Create a vector with some integers
vector<int> v {1, 2, 3, 4};

  // Do a bunch of stuff with the vector...

  // NEW WAY: Add some random values (concise)
for (int i : {7, 11, 18, -5, 0, 42})
  v.push_back(i);
Using a range-based for loop with an initializer list, we can quickly and easily add any set of values. The elements in the initializer don't have to be literals, they can be variables with values not known at compile time.
Notes:

nullptr (N2431)

A new keyword, nullptr has been created to deal with, well, NULL pointers. The type of nullptr is std::nullptr_t. Historically, there have been some problems when mixing NULL, due to the fact that the actual value is implementation-dependent. It is usually defined in C++ to be 0, but is defined in C to be a void pointer:
#define NULL ((void *)0) // C
#define NULL 0           // C++98
For the most part, this wasn't a huge problem, but it did lead to some ambiguities at times. Given these overloaded functions:
void foo(int)
{
  cout << "foo(int)" << endl;
}

void foo(int *)
{
  cout << "foo(int *)" << endl;
}
this code is fine:
foo(0);       // foo(int)
foo(nullptr); // foo(int*), C++11
foo((int*)0); // foo(int*)
but this is ambiguous:
foo(NULL); // possibly ambiguous, depending on how NULL is defined
Clang says:
error: call to 'foo' is ambiguous
  foo(NULL); // possibly ambiguous, depending on how NULL is defined
  ^~~
note: candidate function
void foo(int)
     ^
candidate function
void foo(int *)
     ^
1 error generated.
Notes:

Strongly Typed Enums (N2347)

OK, so what kinds of problems exist with enumerations that require changes to the language? There are several, and I'm going to discuss a few of them.

There are actually 3 things that have changed with respect to enumerations in C++11. In no particular order:

  1. Create a new kind of enum that is strongly typed: enum class
  2. Allow the programmer to choose the underlying type (i.e. sizeof) used to represent the enum.
  3. Allow access to the enum via the scope resolution operator.
Let's start with how enumerations were handled before C++11. Take this simple enumeration:
enum ColorSpace {Red, Green, Blue};     // Represent graphics colors
and use it:
ColorSpace cs = Green; // Set color to green (integer 1)
In C++, enumerations are their own distinct type, so this is illegal:
cs = 1; // ERROR: no conversion from integer
However, this is fine:
int i = Green; // OK, implicit conversion to integer, C++03 only
OK, so far, so good. This is the pre-C++11 behavior. But, we also have this problem:
enum ColorSpace {Red, Green, Blue};     // Represent graphics colors
enum TrafficLight {Red, Yellow, Green}; // Represent traffic signals
Clang says this:
error: redefinition of enumerator 'Red'
  enum ColorSpace {Red, Green, Blue};     // Represent graphics colors
                   ^
note: previous definition is here
  enum TrafficLight {Red, Yellow, Green}; // Represent traffic signals
                     ^
error: redefinition of enumerator 'Green'
  enum ColorSpace {Red, Green, Blue};     // Represent graphics colors
                        ^
note: previous definition is here
  enum TrafficLight {Red, Yellow, Green}; // Represent traffic signals
                                  ^
This has led programmers to do things like this:
enum ColorSpace {csRed, csGreen, csBlue};     // Represent graphics colors
enum TrafficLight {tlRed, tlYellow, tlGreen}; // Represent traffic signals
There is no longer any ambiguity:
ColorSpace color = csGreen;   // OK 
TrafficLight light = tlGreen; // OK
Of course, there are other solutions (e.g. namespaces, static members of a class).

Then there is the issue with this:

sizeof(ColorSpace)
This is compiler-dependent. The only thing the compiler guarantees is that the underlying type used to represent the enumerations is large enough to hold the value of the largest element.

Fortunately, C++11 solves these shortcomings with a feature call enumeration classes:

  // Elements are no longer ambiguous
enum class ColorSpace {Red, Green, Blue};     // Represent graphics colors
enum class TrafficLight {Red, Yellow, Green}; // Represent traffic signals

  // Clear, unambiguous, self-documenting
ColorSpace cs = ColorSpace::Green;
TrafficLight tl = TrafficLight::Green;
However, this is no longer supported:
int i = Color::Green; // No conversion to int in C++11
These are also referred to as scoped enumerations because you access them with the scope resolution operator. Also, the size of the underlying type is guaranteed to be integer (unless you specifically request a different type).

If you leave off the class, you can still use the scope resolution operator. This was an enhancement made to the original enum specification:

enum TrafficLight {Red, Yellow, Green}; // Represent traffic signals

TrafficLight tl = TrafficLight::Green; // Optional qualifier (recommended)
TrafficLight tl2 = Green;              // Same as TrafficLight::Green
However, I would avoid the old-style enumerations, as that can lead to ambiguities. Get into the habit of using the qualified names and you'll never have a problem.

C++11 also lets you choose the representation of the enumeration:

enum class TrafficLight : char {Red, Yellow, Green};  // Represent traffic signals
enum class ColorSpace : short {Red, Green, Blue};     // Represent graphics colors
enum class Twister : long {Red, Green, Blue, Yellow}; // Represent the game colors
enum class Checkers {Red, Black};                     // Represent the game colors

  // Sizes shown are using the LP64 data model  
cout << sizeof(TrafficLight) << endl; // 1
cout << sizeof(ColorSpace) << endl;   // 2
cout << sizeof(Twister) << endl;      // 8
cout << sizeof(Checkers) << endl;     // 4 (default type is int)
Notes: Another thing relating to enumerations that was introduced in C++11 is forward declaration of enumerations (N2764).
enum class ColorSpace : short; // Represent graphics colors (forward declaration)

// Other code ...

enum class ColorSpace : short {Red, Green, Blue}; // Actual definition is here
Notes:

auto Deductions (N1984)

Just as the compiler can (usually) deduce the types of parameters to templated functions, the compiler can now deduce the type of a variable based on it's initializer. It uses the deprecated auto keyword:
auto i = 10;    // int
auto d = 10.0;  // double
auto f = 10.0F; // float
cout << typeid(i).name() << endl; // i
cout << typeid(d).name() << endl; // d
cout << typeid(f).name() << endl; // f
You can also include qualifiers:
const auto ii = 10;    // const int
auto& ri = ii;         // int&
const auto& cri = ii; // const int&
Be careful when using auto:
auto i1 = 1;   // int, as expected
auto i2 = {1}; // initializer_list<int>, probably not what you want
auto i3 {1};   // int, before C++14 it was initializer_list<int>
auto i4(1);    // int

cout << typeid(i1).name() << endl; // i
cout << typeid(i2).name() << endl; // St16initializer_listIiE
cout << typeid(i3).name() << endl; // i
cout << typeid(i4).name() << endl; // i
More examples:
vector<int> v1;

auto x1 = v1.crbegin();
cout << typeid(x1).name() << endl;

vector<int>::const_reverse_iterator x2 = v1.crbegin();
cout << typeid(x2).name() << endl;
Output:
St16reverse_iteratorIN9__gnu_cxx17__normal_iteratorIPKiSt6vectorIiSaIiEEEEE
St16reverse_iteratorIN9__gnu_cxx17__normal_iteratorIPKiSt6vectorIiSaIiEEEEE
Using auto:
  // vector<int>
auto v2(v1);
cout << "   auto v2(v1) is " << typeid(v2).name() << endl;

  // vector<int>
auto v3 = v1;
cout << "  auto v3 = v1 is " << typeid(v3).name() << endl;

  // vector<int>  
auto v4{v1};
cout << "   auto v4{v1} is " << typeid(v4).name() << endl;

  // initializer_list<vector<int>>
auto v5 = {v1};
cout << "auto v5 = {v1} is " << typeid(v5).name() << endl;

  // vector<int> (no auto)
vector<int> v6 = {v1};
cout << "     v6 = {v1} is " << typeid(v6).name() << endl;
Output:
   auto v2(v1) is St6vectorIiSaIiEE
  auto v3 = v1 is St6vectorIiSaIiEE
   auto v4{v1} is St6vectorIiSaIiEE
auto v5 = {v1} is St16initializer_listISt6vectorIiSaIiEEE
     v6 = {v1} is St6vectorIiSaIiEE
The "classic" example for using auto is with iterators in loops. Here's the print5 function using explicitly typed variables:
template <typename T>
void print5a(const T& container)
{
  for (typename T::const_iterator iter = container.begin(); iter != container.end(); ++iter)
    std::cout << *iter << "  ";
  std::cout << std::endl;
}
Using auto:
template <typename T>
void print5b(const T& container)
{
  for (auto iter = container.begin(); iter != container.end(); ++iter)
    std::cout << *iter << "  ";
  std::cout << std::endl;
}
Using auto and range-based for loops:
template <typename T>
void print5(const T& container)
{
  for (auto e : container)
    std::cout << e << "  ";
  std::cout << std::endl;
}
When declaring multiple variables with the auto keyword, they all must be the same type:
auto i = 5, j = 7, *pi = &i; // OK
auto k = 100, d = 3.1415;    // error: inconsistent deduction for auto

vector<int> v1 {1, 2, 3};
for (auto iter = v1.begin(), end = v1.end(); iter != end; ++iter)
  cout << *iter << endl;
Notes:

Raw and Unicode String Literals (N2442)

Here is some sample code from the link above that shows the motivation for raw strings:

    "('(?:[^\\\\']|\\\\.)*'|\"(?:[^\\\\\"]|\\\\.)*\")|"

Are the high-lighted five backslashes correct or not? Even experts become easily confused. Here is the same line as a raw string literal:

    R"(('(?:[^\\']|\\.)*'|"(?:[^\\"]|\\.)*")|)"

Anytime that you need to deal with strings that include characters like backslashes and double-quotes, you end up having to escape them (with the backslash character). This makes the string difficult to parse (for a human). Certain types of text processing requires these "special" characters (e.g. HTML, XML, regular expressions, etc.) Having a more convenient way to code those strings without all of the escaping, is desirable.

This is a mistake that every Windows programmer has made and had to deal with:

std::string text_editor("c:\windows\system32\notepad.exe");
Errors from Clang:
error: unknown escape sequence '\w' [-Werror,-Wunknown-escape-sequence]
  std::string text_editor("c:\windows\system32\notepad.exe");
                             ^~
error: unknown escape sequence '\s' [-Werror,-Wunknown-escape-sequence]
  std::string text_editor("c:\windows\system32\notepad.exe");
                                     ^~
2 errors generated.
The programmer forgot to escape the backslashes (directory delimiters): Because the backslashes are used to delimit subdirectories, the compiler thinks that there are 3 escape sequences: \w, \s, and \n. Of course, \n is a valid escape sequence, but it's unlikely that the text_editor intended to have a newline as part of it. I have seen this exact problem confuse new C/C++ programmers several times.

This is the proper way:

std::string text_editor("c:\\windows\\system32\\notepad.exe");
Using raw strings makes it much simpler:
std::string text_editor(R"(c:\windows\system32\notepad.exe)");
Raw strings are pretty simple. They just tell the compiler to use the strings without any interpretation of the escape sequences.

To construct a raw string:

  1. A raw string must start with R" (capital 'R' only, not lowercase 'r') and a double-quote character.
  2. The R" is then followed by a PREFIX which consists of 0 to 16 characters. Most characters are allowed.
  3. The (optional) PREFIX must be followed by a left parenthesis.
  4. After the left parenthesis, the actual characters of the string will follow and no interpretation is done, i.e. backslashes do not escape anything and double-quotes do not terminate the raw string but are part of it.
  5. The raw string is terminated by a right parenthesis followed by the same PREFIX that was specified in #2.
  6. Finally, a double-quote character terminates the entire sequence.
Examples will clarify. The text in blue is the actual raw string. The normal text on either side are the delimiters that mark the begin and end of the raw text.
const char *s1 = R"(hello)";     // hello
const char *s2 = R"(he"ll"o)";   // he"ll"o
const char *s3 = R"(hel)lo)";    // hel)lo
const char *s4 = R"(h\tello\n)"; // h\tello\n
const char *s5 = R"(R"()";       // R"(
const char *s6 = R"(R"()")";     // ERROR
Output:
hello
he"ll"o
hel)lo
h\tello\n
R"(
This is the error from Clang for the last one:
cpp14.cpp:562:29: error: missing terminating '"' character [-Werror,-Winvalid-pp-token]
  const char *s6 = R"(R"()")";     // ERROR
                            ^
cpp14.cpp:562:28: error: expected ';' at end of declaration
  const char *s6 = R"(R"()")";     // ERROR
                           ^
                           ;
2 errors generated.
What we are trying to do is to print this string:
R"()"
But the sequence )" is what is terminating the raw string:
R"(R")")"
     ^^
If you need to include characters in the raw string that have the same sequence as the delimiter, you need to change the delimiter into something unique. That's why the PREFIX is 0 to 16 characters. If there are no conflicts, you don't need the PREFIX (hence, the optional wording). In this case, we have a conflict so we need to resolve it by creating a PREFIX.

Any character (or set of characters) will do:

const char *s7 = R"x(R"()")x";   // R"()"
The PREFIX is just the character x and is enough to prevent any conflicts. It doesn't matter what character(s) you use, as long as they are not part of the PREFIX.

Non-static Data Member Initializers (N2756)

Before C++11, you could only initialize static, constant integral members in the class definition. All other members were required to be initialized in a constructor. For base classes, members that are user-defined types, constants, and reference, the initialization must take place in the member initializer list. For all other types, you could assign to them in the body of the constructor, although they could still be initialized in the initializer list.

With C++11 and later, you can now initialize members directly in the class definition. This is a welcomed addition that other languages (such as Java and D) have had already. The concept is easy to understand, so let's look at an example.

// Global function
int getnumber()
{
  return 42;
}

class A
{
  public:
    A() : b{7, 8, 9} // initialized by member initializer list
    {
        // Assignment, not initialization (OK, c is non-const)
      for (int i = 0; i < 3; i++)
        c[i] = i;
    }

    A(int x) : i(x), b{x, x, x}
    {
      // c is left uninitialized
    }

    void print()
    {
      cout << i << endl;
      cout << j << endl;
      cout << k << endl;
      cout << d << endl;
      for (auto it : v)
        cout << it << " ";
      cout << endl;
      for (auto it : a)
        cout << it << " ";
      cout << endl;
      for (auto it : b)
        cout << it << " ";
      cout << endl;
      for (auto it : c)
        cout << it << " ";
      cout << endl;
    }

  private:
    int i = 5;             // Member initialization
    int i2 {6};            // Member initialization (New in C++11)
    int i3 = {7};          // Member initialization
    int i4(8);             // This syntax won't work here. *See note below

    int j = getnumber();   // Member initialization (calls member function)
    int k = ::getnumber(); // Member initialization (calls global function)
    double d = 3.14;       // Member initialization

    vector<int> v{1, 2, 3};   // Member initialization (vector constructor)

    const int a[3] {0, 0, 0}; // const can be initialized here
    const int b[3];           //   or using the member initializer list in the constructor
    int c[3];                 // Non-const can be assigned in the constructor

    // private member function
    int getnumber()
    {
      return 32;
    }
};
There aren't too many rules about what can be initialized in the class definition, but you can read more about it.

Trailing Return Types (N3276)

I'm going to introduce some new syntax using trivial examples. However, these techniques should never be used for trivial functions, as they cause more problems than they solve. Actually, they don't solve anything, they just create problems. But, before I show you the advanced reasons for using these techniques, I want you to understand what's going on.

In C++03, the programmer had to specify the return type for a function as the first part of the function header:
int Add(int a, int b)
{
  return a + b;
}
This is all fine and good. C++11 allows you to specify the return type at the end of the function header instead of the beginning:
auto Add(int a, int b) -> int
{
  return a + b;
}
At first glance, you may be thinking that this isn't doing anything helpful. In this trivial example, you're correct. It was meant for much more complicated things (as you'll soon see). Also, some languages actually specify their return types at the end, and, IMHO, I find those functions easier to read. Some examples:
foo(int, int, int) -> long;
foo(const char *) -> std::string;
The first one is a function that takes 3 integers as input and returns a long integer. The second function takes a constant character pointer and returns a std::string. It's really just a matter of preference as there is really no benefit to either.

The primary reason for this was to help deduce returns from templated functions:

template <typename T, typename U>
auto Add(T a, U b) -> decltype(a + b)
{
  return a + b;
}
Call the function:
int i1 = 5, i2 = 6;
double d1 = 2.72, d2 = 3.14;

cout << Add(i1, i2) << endl; // return type is int
cout << Add(d1, d2) << endl; // return type is double
cout << Add(i1, d2) << endl; // return type is double
Notice the new keyword decltype at the end. This tells the compiler to "figure out" what the return type will be based on the two template parameters. Also, it must come at the end of the function header and not the beginning:
template <typename T, typename U>
decltype(a + b) Add(T a, U b)
{
  return a + b;
}
Error from Clang:
error: use of undeclared identifier 'a'
decltype(a + b) Add(T a, U b) ->
         ^
error: use of undeclared identifier 'b'
decltype(a + b) Add(T a, U b) ->
             ^
This is simply because the compiler hasn't seen a or b yet. This is why it's at the end.
C++14 has taken this one step further and automatically deduces the return type, so you don't even need to specify it at the end:
auto Add(int a, int b)
{
  return a + b;
}
And with the templated function above:
template <typename T, typename U>
auto Add(T a, U b)
{
  return a + b; // The compiler figures out the return type
}
Realize that if there are multiple return calls, they all must be the same type:
template <typename T, typename U>
auto max(T a, U b)
{
  if (a > b)
    return a;
  else
    return b; // a and b can be different types
}

cout << max(1, 2.0) << endl; // Call max with different types
Error from Clang:
error: 'auto' in return type deduced as 'double' here but deduced as 'int' in earlier return statement
    return b;
    ^
Notes:

__func__ Predefined Identifier (N2340)

Before C++11, many compilers used a non-standard way of identifying the name of the function during compilation:
void SomeFunction()
{
  cout << "Function name is: " << __FUNCTION__ << endl; // Old non-standard extension
}
Output:
Function name is: SomeFunction
C++11 has standardized it with __func__:
cout << "In function: " << __func__ << endl; // The name of the function
cout << "    in file: " << __FILE__ << endl; // The name of the C++ file
cout << "    at line: " << __LINE__ << endl; // The current line number
cout << "         on: " << __DATE__ << endl; // The current date
cout << "         at: " << __TIME__ << endl; // The current time
Output:
In function: f13
    in file: cpp14.cpp
    at line: 991
         on: Apr 16 2018
         at: 14:01:20
The test function is named f13.

It is unfortunate that all of the other similar techniques use all uppercase names. This is due to the fact that __func__ is implemented by the compiler and the others are expanded by the pre-processor. To "prove" this, I just compiled the code with the -E option (show the pre-processed code):

cout << "In function: " << __func__ << endl;
cout << "    in file: " << "cpp14.cpp" << endl;
cout << "    at line: " << 991 << endl;
cout << "         on: " << "Apr 16 2018" << endl;
cout << "         at: " << "14:03:40" << endl;

The purpose of __func__ is to help with diagnostic messages at runtime. You can easily build up an informative error message with the aid of these features:

cout << "An out-of-range error has occurred in file " << __FILE__
     << " at line " << __LINE__
     << " (in function " << __func__ << ").\n"
     << "The software was last compiled on " << __DATE__
     << " at " << __TIME__ << ".\n";
Output:
An out-of-range error has occurred in file cpp14.cpp at line 997 (in function f13).
The software was last compiled on Apr 16 2018 at 14:05:14.

Notes: Standard Predefined Macros This page lists some of the other macros that are available.

Delegating Constructors (N1986)

Delegating constructors is a fancy way of saying that one constructor can call another constructor. In this scenario, I'm not talking about a derived class constructor calling a base class constructor. That has been around since the beginning. I'm talking about one constructor of a class calling another constructor of the same class. Until this feature came around in C++11, this was not allowed by the language. C++ programmers have done all sorts of things to get around this situation (as other languages, such as Java and D, already have this capability.)

Constructors are generally the place to initialize members of the class. It's not uncommon to have more than one constructor, so this "initialization code" needed to be duplicated in several places. Or, better yet, this "duplicated" code was factored out into a separate init(...) method that was then called from each constructor:

class C1
{
  public:
      // Default constructor
    C1() 
    {
      init(); // Do other setup code...
    }

      // Single-argument conversion constructor
    C1(double x) : d_(x)
    {
      init(); // Do other setup code...
    }

      // Non-default constructor
    C1(int a, int b, int c, double d) : a_(a), b_(b), c_(c), d_(d)
    {
      init(); // Do other setup code...
    }

  private:
    int a_, b_, c_;
    double d_;

    void init()
    {
       // Do a lot of setup stuff
    }
};
Although we have factored out the common "initialization" code, it's not really initialization because that must take place in the constructor's member initializer list, not another method (even if you name it init!)

With delegating constructors, we can just call the "main" constructor that will do all of the initialization:

class C2
{
  public:
      // Default constructor
    C2() : C2(0, 0, 0, 0.0) // delegate to other constructor
    {
    }

      // Single-argument conversion constructor
    C2(double x) : C2(0, 0, 0, x) // delegate to other constructor
    {
    }

      // Non-default constructor
    C2(int a, int b, int c, double d) : a_(a), b_(b), c_(c), d_(d) // maybe more initialization here...
    {
      // Do a lot of setup stuff
    }

  private:
    int a_, b_, c_;
    double d_;
};
Notes:

noexcept ()

Previous versions of C++ have had exception specifications. This was a mechanism that allowed the programmer to "tag" functions with the types of exceptions that might be thrown. For example, this lookup function can potentially throw an exception if the index is out of range:
int lookup(const vector<int>& v, int index) throw(std::out_of_range)
{
  return v.at(index); // This method does range checking
}
The code at the end:
throw (std::out_of_range)
is the exception specification and informs the programmer what may be thrown from the function. It also tells the compiler to prevent any other exceptions from being thrown. If any exception, other than std::out_of_range is thrown, the entire program is terminated.

This is sample code that calls the function above:

vector<int> v {10, 20, 30};
try
{
  cout << lookup(v, 2) << endl; // Prints 30
  cout << lookup(v, 5) << endl; // Throws a std::out_of_range exception
}
catch (const std::out_of_range& ex)
{
  cout << ex.what() << endl; // Display details about the exception
}
Output:
30
vector::_M_range_check: __n (which is 5) >= this->size() (which is 3)

There are 3 varieties of exception specifications:
// foo1 will throw no exceptions
int foo1() throw();

// foo2 will only throw std::out_of_range or std:bad_alloc
int foo2() throw (std::out_of_range, std::bad_alloc);

// foo3 may thrown any exception
int foo3();
  1. foo1 - An empty exception specification may not throw any exception.
  2. foo2 - A non-empty exception specification may only throw the exceptions listed.
  3. foo3 - A missing exception specification may throw any exception.
For various reasons, exception specifications never worked out as intended and have been deprecated for several years. Now, with C++11, there is a replacement. As it turns out, the important information that the compiler wants to know is if the function throws an exception or not. The compiler doesn't care about which exception is thrown. The new technique reflects this change:
// Function will not throw an exception
void foobar1() noexcept(true)
{
  // do something safe
}

// Function may throw an exception
void foobar2() noexcept(false)
{
  // do something possibly unsafe
}

// foobar3 may throw an exception only if foobar2 may throw an exception
void foobar3() noexcept(noexcept(foobar2()))  
{
  foobar2(); // call possibly unsafe function
}

// foobar4 will not throw an exception (protects unsafe call to foobar2)
void foobar4() noexcept(true)  
{
  try
  {
    foobar2(); // call possibly unsafe function
  }
  catch (.../* whatever foobar2 throws */)
  {
    // do something with the exception
  }

  // safely continue excecuting...
}
Examples showing a noexcept expression:
cout << boolalpha;
cout << "  noexcept(true)? " << noexcept(true) << endl;
cout << " noexcept(false)? " << noexcept(false) << endl;
cout << "foobar1 noexcept? " << noexcept(foobar1()) << endl;
cout << "foobar2 noexcept? " << noexcept(foobar2()) << endl;
cout << "foobar3 noexcept? " << noexcept(foobar3()) << endl;
cout << "foobar4 noexcept? " << noexcept(foobar4()) << endl;
Output:
  noexcept(true)? true
 noexcept(false)? true
foobar1 noexcept? true
foobar2 noexcept? false
foobar3 noexcept? false
foobar4 noexcept? true
When declaring a function to be noexcept, these both mean the same thing:
void foobar() noexcept(true) // explicit
void foobar() noexcept       // implicit
On a side note, it's a little unfortunate that the terminology kind of reverses the definition of on/true/enabled with off/false/disabled. By setting noexcept to true, you are disabling the ability to throw exceptions. It has always seemed strange to me when you "turn something off" by answering in the affirmative:
Q: "Do you want me to not turn the lights off?"
A: Yes, please do not turn them off.
Most English speakers will ask in the affirmative:
Q: "Do you want me to turn the lights off?"
A: No, please do not turn them off.
This would mean we would have except(true) to allow exceptions and except(false) to not allow them. Anyhoo...

Notes:

Generalized constexpr (N2235)

C++11 introduces a new way of dealing with constant expressions. You can now explicitly mark a symbol with the constexpr keyword. This is more powerful than simply using const alone. Using just const means that the expression is constant and won't change, but it doesn't mean that the value is known at compile-time:
const int i = getvalue1(); // Sets i at runtime. Must be initialized because it's const
int array[i];              // Illegal, i isn't known at compile time. 
In the code above, getvalue1() is just some arbitrary function that will return an integer when called. However, the value returned isn't known to the compiler and can't be used to set the size of the array. With the constexpr keyword, things change.

Here are 4 functions for the examples below:

constexpr int ipower(int base, int exponent)
{
  int p = 1;
  
  for (int i = 0; i < exponent; i++)
    p *= base;

  return p;
}
constexpr int squared(int x)
{
  return x * x;
}
int getvalue1()
{
  return 10;
}
constexpr int getvalue2()
{
  return 20;
}
Code that calls the above functions:
int a1[getvalue1()];            // Illegal, getvalue1() isn't known at compile-time
int a2[getvalue2()];            // OK, constant expression

const int v1 = getvalue1();     // OK, but v1 isn't known at compile-time (not constexpr)
int a3[v1];                     // Illegal

const int v2 = getvalue2();     // OK, but v2 is not constexpr
int a4[v2];                     // Illegal

constexpr int v3 = getvalue1(); // Illegal, can't initialize v3 with non-constexpr

constexpr int v4 = getvalue2(); // OK
int a5[v4];                     // OK

int a6[squared(5)];             // OK
cout << sizeof(a6) << endl;     // prints 100 (25 * 4)

int a7[squared(getvalue1())];   // Illegal, getvalue1 is not constexpr
int a8[squared(getvalue2())];   // OK
cout << sizeof(a8) << endl;     // prints 1600 (400 * 4)

int a9[ipower(2, 3)];            // OK
cout << sizeof(a9) << endl;     // prints 32 (8 * 4)
Notes:

Template Aliases (N2258)

In C++03, if you want to define an alias for a type, you used typedef:
typedef unsigned char BYTE;
typedef short int FAST_INT;
typedef float CURRENCY;
typedef unsigned char * PCHAR;
Using them:
BYTE next, previous;    // For scanning bytes in memory
CURRENCY tax, discount; // To calculate total price
PCHAR inbuf, outbuf;    // To manipulate strings
The equivalent with the using keyword (new in C++11):
using BYTE = unsigned char;
using FAST_INT = short int;
using CURRENCY = float;
using PCHAR = unsigned char *;
We can use typedef with the STL containers:
typedef vector<int> MyVectorI;    // MyVectorI is an alias for vector of int
typedef vector<string> MyVectorS; // MyVectorS is an alias for vector of string
typedef vector<double> MyVectorD; // MyVectorD is an alias for vector of double
Usage:
MyVectorI mvi; // vector of int
MyVectorS mvs; // vector of string
MyVectorD mvd; // vector of double
At this point there is absolutely no difference in behavior between typedef and using. However, when it comes to templates, there is a problem with typedef:
template <typename T>
typedef vector<T> MyVectorOfT;
Error from Clang:
error: a typedef cannot be a template
typedef vector MyVectorOfT;
                  ^
1 error generated.
This is where the new behavior of using comes in:
template <typename T>
using MyVector = vector<T>; // MyVector is an alias for a vector anything
Usage:
MyVector<int> vi2;    // vector of int
MyVector<string> vs2; // vector of string
MyVector<double> vd2; // vector of double
At this point, there is not much to be gained. But as the types get more complicated:
template <typename T>
using MyVectorT = vector<list<T>>; // MyVectorT is an alias for a vector of list of anything

MyVectorT<int> vli;    // vector of list of int
MyVectorT<string> vls; // vector of list string
MyVectorT<double> vli; // vector of list of double
Or this:
template <typename T, typename Alloc = std::allocator<T>>
using MyIter = typename vector<list<T, Alloc>>::iterator;

MyIter<string> it1;       // An iterator on a vector of lists of string and the default allocator
MyIter<Foo, MyAlloc> it2; // An iterator on a vector of lists of Foo and custom allocator
Yes, that's a little contrived. However, in real code, you are likely to have instances where the types are complicated and tedious to write out, especially when you start using templates.

Notes:

Lambdas (N2927)

I've already written a substantial guide on lambdas here.

Long Long Data Type (N1811)

Until C++11, the long long type has been a non-standard extension to compilers. Almost all compilers have supported the type, but now it is officially part of the C++ standard. The standard guarantees that a long long is at least 64-bits. This may seem redundant because the long data type is already 64-bits for most systems.

There are two situations where I think this type will be useful:

  1. The long long type allows implementations to use more than 64-bits, possibly 128-bits, for an integral type.
  2. It allows Microsoft's code to work with the rest of the world. Microsoft's Windows OS is currently the only popular 64-bit system that still uses 32-bits for long integers. Programmers on Windows should use long long if they want a 64-bit data type. (64-bit data models shows the sizes of data types on common systems.)
The table below shows the differences from Microsoft's systems and most others. Microsoft's types are in the shaded region:
Type Bytes Also called Range of values
(Binary)
Range of values
(Decimal)
signed long int 8 long
long int
signed long
-263 to 263 - 1 -9,223,372,036,854,775,808 to
9,223,372,036,854,775,807
unsigned long int 8 unsigned long 0 to 264 - 1 0 to 18,446,744,073,709,551,615
signed long int 4 long
long int
signed long
-231 to 231 - 1 -2,147,483,648 to
2,147,483,647
unsigned long int 4 unsigned long 0 to 232 - 1 0 to 4,294,967,295
The long long type is signed, and as you would expect, there is an unsigned version as well: unsigned long long. For literals, there are also new suffixes:
long long ll = 12345LL;            // LL for (signed) long long
unsigned long long ull = 12345ULL; // ULL for unsigned long long
The extraction operator (>>) and insertion operator (<<) have been overloaded for the new types:
cin >> ll;
cin >> ull;

cout << ll << endl;
cout << ull << endl;
For printf and scanf:
scanf("%lli", &ll);    // Can also use %lld
scanf("%llu", &ull);

printf("%lli\n", ll);  // Can also use %lld
printf("%llu\n", ull);

Default and Deleted Functions (N2346)

These two topics, default functions and deleted functions, are somewhat related. And, since most of the literature on C++11 groups them into one, I'm going to do the same.

Default Functions:

In C++, when you create a class, by default you get these member functions for free:

  1. A default constructor (that does nothing)
  2. A destructor (that does nothing)
  3. A copy constructor (that does memberwise copy)
  4. A copy assignment operator (that does memberwise assignment)
If necessary, the compiler will generate these methods for you. For trivial classes, the compiler-generated methods are adequate. For example, class Foo4 is trivial:
class Foo4
{
  public:
    friend ostream& operator<<(ostream& os, const Foo4& rhs);
  private:
    int a = rand() % 10;
    int b = rand() % 10;
};

ostream& operator<<(ostream& os, const Foo4& rhs)
{
  os << rhs.a << ", " << rhs.b;
  return os;
}
The operator<< function is just for convenience and doesn't really add anything important to this discussion.
void f23()
{
  Foo4 f1;     // default constructor (compiler-generated)
  Foo4 f2;     // default constructor (compiler-generated)
  Foo4 f3(f1); // copy constructor (compiler-generated)

  cout << "f1: " << f1 << endl; // f1: 3, 6
  cout << "f2: " << f2 << endl; // f2: 7, 5
  cout << "f3: " << f3 << endl; // f3: 3, 6

  f1 = f2;     // copy assignment (compiler-generated)
  cout << "f1: " << f1 << endl; // f1: 7, 5

} // destructor (compiler-generated) called for f1, f2, f3
If the compiler-generated methods are not adequate, then you will have to implement them yourself. If you implement one of these methods, then the compiler will not generate one, which makes sense. However, if you implement a constructor (any constructor other than the copy constructor), then the compiler will not generate the default constructor:
class Foo4
{
  public:
    Foo4(int i, int j) : a(i), b(j) {} // non-default constructor
    friend ostream& operator<<(ostream& os, const Foo4& rhs);
  private:
    int a = rand() % 10;
    int b = rand() % 10;
};
Now this, which was previously fine, gives an error:
Foo4 f1;     // default constructor
Error:
error: no matching constructor for initialization of 'Foo4'
  Foo4 f1;     // default constructor
With the programmer-implemented constructor, we must provide 2 integers to the constructor:
Foo4 f4(1, 2); // non-default constructor
cout << "f4: " << f4 << endl; // f4: 1, 2
But, what if we still want the default constructor? In the olden days (read: C++98/03), you had to implement it yourself:
class Foo4
{
  public:
    Foo4() {} // default constructor (programmer-implemented, does nothing)
    Foo4(int i, int j) : a(i), b(j) {}
    ...
};
Now, the code that generated errors for this missing default constructor is working again.

With C++11, you can just instruct the compiler to generate the default constructor instead of the programmer. You do this by appending = default to the default constructor's declaration:

class Foo4
{
  public:
    Foo4() = default; // compiler will generate this
    Foo4(int i, int j) : a(i), b(j) {}
    ...
};

Another place where you might want to use this technique is with virtual destructors. By default, compiler-generated destructors are not virtual. If you're planning on using your class as a base class, you will likely need your destructor to be virtual, even if your destructor does nothing at all. In pre-C++11 days, the programmer would have to implement an empty destructor so that it could be marked virtual:

class Foo4
{
  public:
    virtual ~Foo4() {} // empty destructor to get virtual behavior
    ...
};
With C++11, you can use the default keyword to have the compiler generate the destructor as virtual:
class Foo4
{
  public:
    virtual ~Foo4() = default // compiler will generate the virtual destructor
    ...
};
You may be thinking that it really wasn't that much effort to implement the empty default constructor/destructor yourself, and you'd be correct. However, whenever the compiler generates methods for you, it has an opportunity to optimize them, meaning, at runtime, the compiler-generated methods may not even be called, saving some time.

Deleted Functions

With the discussion of default functions above, the point was to force the compiler to generate some methods that otherwise would not have been generated. But, what if we want the opposite behavior? Meaning, you don't want the compiler to generate certain functions for you? With classes, the function that comes to mind is the copy constructor.

Most of the time, you need to be able to make copies of objects. However, there are situations where you don't want to allow the user to make copies. In old C++, the way that the programmer made sure that no copies were made was to declare the copy constructor in the private section of the class:

class Foo4
{
  public:
    ...
  private:
    Foo4(const Foo4& rhs); // copy constructor, do not implement!
    int a = rand() % 10;
    int b = rand() % 10;
};
Now this code will fail to compile:
Foo4 f3(f1); // call copy constructor
with this error:
error: calling a private constructor of class 'Foo4'
  Foo4 f3(f1); // copy constructor (compiler-generated)
       ^
Like with the = default, there is now = delete which prevents the compiler from generating unwanted functions:
class Foo4
{
  public:
    Foo4(const Foo4& rhs) = delete; // copy constructor won't be generated
    ...
};
If you try to call a deleted function, you'll get an error similar to this:
error: call to deleted constructor of 'Foo4'
  Foo4 f3(f1); // copy constructor (compiler-generated)
       ^  ~~
note: 'Foo4' has been explicitly marked deleted here
    Foo4(const Foo4&) = delete;
    ^
I won't go into the (advanced) reasons why you might not want to allow copies, but there is one popular class (possibly the most popular) that disallows copying. That class is basic_ios, which is a base class for ostream which is the type of cout. This means that you can't make a copy of cout. Beginning programmers may have fallen into this trap when they learn how to overload operator << to print out their data:
friend ostream& operator<<(ostream os, const Foo4& rhs);
The problem with the code above is that ostream is passed by value, which means that a copy will be made. But, because the copy constructor has been marked as deleted, this will generate an error similar to this:
error: call to deleted constructor of 'ostream' (aka 'basic_ostream')
  cout << "f1: " << f1 << endl; // f1: 3, 6
  ^~~~~~~~~~~~~~
I won't go into all of the reasons why you'd want to choose to mark a method as deleted instead of just declaring it in the private section, but here's one: The private function can still be called by the class itself. Of course, without an implementation you will get a linker error. Ideally, you would like to get a compiler error instead, as it's generally easier to figure out what the problem is than it is with linker errors. A large project may not be linked very often, but code changes are compiled constantly. By using = delete you will get a compiler error from any code that tries to call it.

Preventing copies has been a popular reason to put the copy constructor declaration in the private section, and now you can just mark it as deleted. But, = delete doesn't need to be used in a class. Any function can be marked deleted. At first glance, that seems absurd. If you don't want a user to call a certain non-member function, then don't create it!

However, consider this function:

bool isEven(long value)
{
  if (value % 2)
    return false;
  else
    return true;
}
And a few uses:
long j = 8;
float f = 8.0F;
double d = 8.0;
cout << boolalpha <<  isEven(j) << endl; // long, OK (true)
cout << boolalpha <<  isEven(f) << endl; // float to long, OK (true)
cout << boolalpha <<  isEven(d) << endl; // double to long, (true)
Because the compiler performs implicit conversions, all of these calls can succeed. But, suppose you don't want to allow this. Marking the overloaded declarations as deleted will do the trick:
bool isEven(float) = delete;  // declaration only
bool isEven(double) = delete; // declaration only
Now, passing a float or double will generate these errors:
 error: use of deleted function 'bool isEven(float)'
   cout << boolalpha <<  isEven(f) << endl; // float to long, OK
                                 ^
note: declared here
 bool isEven(float) = delete;
      ^
 error: use of deleted function 'bool isEven(double)'
   cout << boolalpha <<  isEven(d) << endl; // double to long, OK
                                 ^
note: declared here
 bool isEven(double) = delete;
      ^
Another place you might use this technique is with function templates. If you want to prevent the compiler from generating a certain version of the template, you can create a specialization for that type and mark it as deleted.

Information from Stroustrup's site.

std::array

Yeah, I know I said that I wasn't going to cover additions/changes to the STL, but I've changed my mind. There has been a new container added to the STL. It's the std::array. This class is basically a thin wrapper around the built-in C-style static arrays you've been using since forever. We'll see shortly why you should use this as a replacement to the built-in arrays.

First, let's compare the syntax of std::array with the built-in static array. You can also assume that I have a function that can print a static array and another function that can print out a std::array. I'll show you how to implement those later.

To use std::array, you must include this:

#include <array>
Since std::array is a templated class requiring two parameters. The first template parameter is a type (e.g. int, double, Foo, etc.) The second template parameter is an integral value, which will be used as the size of the array (e.g. 3, 5, 100, etc.) So, to create a std::array of 5 doubles, you would do this:
array<double, 5> ar; // ar represents a static array of 5 doubles, e.g. double ar[5];

Just like with built-in arrays, without proper initialization, we get undefined values:

array<int, 3> a1; // undefined values: 32615, 1876, 3
int s1[3];        // undefined values: -891498544, 32767, 6299136
Default initialization:
array<int, 3> a2{}; // default initialized to 0 (default constructor)
int s2[3] = {};     // default initialized to 0 (Not legal in C, use {0})
Using explicit initializers:
array<int, 3> a3{1, 2, 3}; // OK
int s3[3] = {1, 2, 3};     // OK
Like built-in arrays, if you provide too many initializers, it's an error:
array<int, 3> a4{1, 2, 3, 4}; // ERROR: too many initializers
int s4[3] = {1, 2, 3, 4};     // ERROR: too many initializers
With built-in arrays, if you provide initializers, you can omit the size. You can't do that with std::array:
array<int> a5{1, 2, 3, 4}; // ERROR: no size specified (compiler won't help here) 
int s5[] = {1, 2, 3, 4};   // OK: compiler sets size to 4 from initializers
Error from g++:
In function 'void f1()':
error: wrong number of template arguments (1, should be 2)
   array a5{1, 2, 3, 4}; // ERROR: no size specified
            ^
Like built-in arrays, if you provide too few initializers, the compiler will set the remaining elements to 0:
array<int, 3> a4{1, 2}; // Too few initializers, rest are 0
int s4[3] = {1, 2};     // Too few initializers, rest are 0


Ok, so now that we've got all of the syntax out of the way you're probably saying, "So what?!? This doesn't give us anything more than what the built-in arrays give us." And you would be right.

In fact, built-in arrays actually give us more than what we have now because we can't do this with std::array:

int s5[] = {1, 2, 3, 4};    // The compiler will figure out the size.
std::array ar {1, 2, 3, 4}; // Error! Must specify type and size
Update: In C++17, we have this new feature called Class Template Argument Deduction (CTAD). This means that now templated classes can deduce their template types and do not require the programmer to provide them. This was possible with templated functions before, but not with templated classes. Now, you can let the compiler figure out the type and the size from the initializer:
  // New in C++17. Class Template Argument Deduction
  // ar is deduced as std::array<int, 4>
std::array ar {1, 2, 3, 4}; 
There is one caveat to this, though. You must either specify ALL of the template arguments, or none of them. If you only specify the type, it is an error:
array<int> ar5 {1, 2, 3}; // ERROR, too few template arguments
Here are some valid and invalid uses:
array         ar1 {1, 2, 3}; // OK, size is 3, values: 1,2,3
array<int, 3> ar2 {1, 2, 3}; // OK, size is 3, values: 1,2,3
array<int, 5> ar3 {1, 2, 3}; // OK, size is 5, values: 1,2,3,0,0
array<int, 5> ar4;           // OK, size is 5, values are all undefined
array<int, 5> ar5 {};        // OK, size is 5, values: 0,0,0,0,0
array<int, 2> ar6 {1, 2, 3}; // ERROR, too many initializers
array<int>    ar7 {1, 2, 3}; // ERROR, too few template arguments
array         ar8;           // ERROR, can't deduce template parameters
Now, there is nothing a std::array can't do that a static (raw) array can do. But std::array can do so much more!

BTW, class argument template deduction can be a pretty complex thing, but you don't have to understand any of it to use it correctly with std::array. For more information, follow these links. But be aware, it is not for the faint-of-heart!

Template argument deduction for class templates (P0091R3).
Filling holes in Class Template Argument Deduction (P1021R5).

Improvements over static arrays

Ok, so the first improvement we have over built-in arrays is that a std::array knows its size. This means that we can query the array at any time in the program to find out the size. This is especially useful when we pass the std::array to a function. With built-in arrays, we can only pass a pointer to the first element to the function. We have to pass a second parameter (the size) to the function and this can be a source of bugs if the incorrect size is passed. We don't have to do this with std::array.

Here's the classic function to print any array of integers:

void print(const int *arr, int size)
{
  for (int i = 0; i < size; i++)
    std::cout << arr[i] << std::endl;
}
To print a std::array of 3 integers, the function would look like this:
void print3ints1(const std::array<int, 3>& arr)
{
  for (int i = 0; i < 3; i++)
    std::cout << arr[i] << std::endl;
}
Since std::array is an STL container, it has a size() method, so we can use that:
void print3ints2(const std::array<int, 3>& arr)
{
  for (size_t i = 0; i < arr.size(); i++)
    std::cout << arr[i] << std::endl;
}
Since it has a size() method, we can use the range-based for instead:
void print3ints3(const std::array<int, 3>& arr)
{
  for (int i : arr)
    std::cout << i << std::endl;
}
Of course, this isn't going to help us print any of these:
array<int, 2> a7{1, 2};             // array of 2 ints
array<double, 3> a8{1.1, 2.2, 3.3}; // array of 3 doubles
We would need something like these:
void print2ints(const std::array<int, 2>& arr)
{
  for (int i : arr)
    std::cout << i << std::endl;
}

void print4doubles(const std::array<double, 4>& arr)
{
  for (double d : arr)
    std::cout << d << std::endl;
}
Nor will it print an array of Foo objects, or std::string, or whatever else we need. Of course, the obvious solution is to templatize the function:
template <typename T, size_t size>
void print(const std::array<T, size>& arr)
{
  for (const T& t : arr)
    std::cout << t << std::endl;
}
Now, we can print a std::array of any type and any size, as long as output operator has been overloaded for type T.
Some of the benefits of using a std::array over a built-in array: How does std::array compare with std::vector? How to choose between std::array and std::vector: More information about std::array.

Structured Bindings (P0144R2)

Structured bindings are a way that you can initialize more than one entity at a time from an aggregate data type. As the name implies, the most common use is with structures (and by extension, classes), although they can be used with other aggregate types such as static arrays and vectors.

Note: This was added in C++ 17 so, depending on the version of your compiler, you may need to use std=c++17 for these examples to work.

Using structured bindings with structures

First, let's look at how we would do things without structured bindings. Suppose we have this very simple structure:

struct Student
{
  int age;
  double gpa;
};
and some usage:
Student s {42, 3.14};

int a = s.age;
double g = s.gpa;

cout << a << ", " << g << endl;
Output:

  42, 3.14

Although this is all fine and good, it can become tedious to do this a lot, especially if there are several members of the structure. Enter structured bindings:

  // x is an int and gets the value 42
  // y is a double and gets the value 3.14
  // x and y are copies of the structure members
auto [x, y] = student;
cout << "x is " << x << ", y is " << y << endl;
cout << "student.age is " << student.age << ", student.gpa is " << student.gpa << endl;
Output:
x is 42, y is 3.14
student.age is 42, student.gpa is 3.14
Note that you must use the auto keyword. Even if both members of the structure are the same type. For example, if both members were integers, you can not do this:
int [x, y] = struct2ints; // assume the structure only contains 2 integers
Error message:
error: structured binding declaration cannot have type 'int'
   int [x, y] = struct2ints; // assume the structure only contains 2 integers
       ^~~~~~
note: type must be cv-qualified 'auto' or reference to cv-qualified 'auto'

This is another reason why the auto keyword was (re)introduced into the language. The syntax would be unnecessarily complicated if each structure member had a different type, as is the case with most structures.

Since x and y above are copies, changing either of them has no effect on student:
  // Modifying x and y does not affect s.age or s.gpa in any way
x = 10;
y = 3.75;

cout << "x is " << x << ", y is " << y << endl;
cout << "student.age is " << student.age << ", student.gpa is " << student.gpa << endl;
Output:
x is 10, y is 3.75
student.age is 42, student.gpa is 3.14
However, if we want to affect the student object, we can bind with references:
  // rx and ry are references
auto& [rx, ry] = student;

rx = 10;            // Modifies rx and s.age (they refer to the same object)
student.gpa = 3.75; // Modifies s.gpa and ry (they refer to the same object)

cout << "rx is " << rx << ", ry is " << ry << endl;
cout << "student.age is " << student.age << ", student.gpa is " << student.gpa << endl;
Output:
rx is 10, ry is 3.75
student.age is 10, student.gpa is 3.75
To "prove" it, we can examine the address of each entity:
cout << "         Address of rx is " << &rx << endl;
cout << "Address of student.age is " << &student.age << endl;
cout << "         Address of ry is " << &ry << endl;
cout << "Address of student.gpa is " << &student.gpa << endl;
Output:
         Address of rx is 0x7fff8bb5c860
Address of student.age is 0x7fff8bb5c860
         Address of ry is 0x7fff8bb5c868
Address of student.gpa is 0x7fff8bb5c868
Note that the number of variables must match the number of fields in the structure:

auto [x] = student;       // Error, not enough variables
auto [i, j, k] = student; // Error, too many variables
Too few:
error: only 1 name provided for structured binding
   auto [x] = student;
        ^~~
note: while 'Student' decomposes into 2 elements
Too many:
error: 3 names provided for structured binding
   auto [i, j, k] = student;
        ^~~~~~~~~
note: while 'Student' decomposes into 2 elements
Another situation where this comes in handy is when we return a structure from a function. Because C++ can only return a single entity from a function, we have devised various ways to work around that limitation. We've passed pointers into functions (e.g. scanf) to retrieve multiple values and we've returned structures. In C++, using std::pair is a popular way to return 2 entities and in more recent versions of C++ we're able to return many values by using std::tuple.

Structured bindings provide a cleaner syntax to accomplish that:

A function that needs to return a structure:

Student create_student(int age, double gpa)
{
  return Student {age, gpa};
}
Now, the caller can easily extract the members of the structure and give them meaningful names:
  // age is 42, gpa is 3.14
auto [age, gpa] = create_student(42, 3.14);


Using structured bindings with static arrays

This is fairly straight-forward:

  // sizeof(array) is known at compile-time
int array[] {1, 2, 3};

  // a is 1, b is 2, c is 3
auto [a, b, c] = array;
As with structures, the number of variables must match the number of elements in the array. Because the size of a static array is known at compile-time, structured bindings work. Remember, that if you pass the array to a function, it will decay into a pointer to the first element and its size will not be known within the function, even if you pass the size as a separate argument.

However, this limitation is easily worked-around by using std::array instead of a static array:

std::array<int, 3> foo(const std::array<int, 4>& array)
{
    // The variables contain copies of the 4 elements in array
  auto [a, b, c, d] = array;

    // Create an array with the first 3 elements above and return it
  return std::array<int, 3> {a, b, c};
}
Call the function:
std::array<int, 3> retval = foo(std::array{1, 2, 3, 4});

  // x is 1, y is 2, z is 3
auto [x, y, z] = retval;
This is another reason to prefer std::array over static (raw) arrays.

Also, notice how in function foo above there is no warning for the unused, but set value of d. This is because it may (often) be the case that you don't need all of the variables, yet you still must bind something to each element.

I don't believe the standard says anything about the warnings being emitted, but both g++ and clang++ do not emit a warning. See section 3.8 of this document p0144r2.pdf for more insight.

Personally, I'd like to see this be allowed in the future:

  // sizeof(array) is known at compile-time
int array[] {1, 2, 3};

  // Only extract the first two elements (ignore the third element) 
auto [a, b] = array;
Or, for a really sweet feature (skip over existing elements):
  // sizeof(array) is known at compile-time
int array[] {1, 2, 3};

  // Only extract the first and third element (ignore the second)
auto [a, ,b] = array;
Both techniques above can be collapsed into one technique. That is, ignoring specific elements regardless of their positions. Some research shows that this has actually been considered and has not been declared "NO", but "not yet", possibly waiting until some motivation for it is encountered. See section 3.8 of p0144r2.pdf for some rationale.
What about using structured bindings with a std::vector? Unfortunately, it won't work for the simple reason that the size of the vector is not known at compile-time. However, it is possible to implement a tuple-like API for a vector but that is way beyond the scope of this introduction.

There are many other things you can do with structure bindings (e.g. bit-fields, user-defined types, etc.) that are also beyond the scope of this introduction. Search the web for more details.


Using structured bindings with tuples

We've already had the ability to return multiple values from a function via a structure of some sort. However, the need to create names/definitions for all of the various structures that we would want to return will become tedious, not to mention polluting the namespace with many single-use structures. The solution is now to use tuples. An example will help clarify.

Suppose we want to calculate the quadratic formula:

      
The first "problem" is that there are two results, so we need a way to return two values from our function. However, what if we divide by zero? This is a problem that will need to be addressed. Also, what if we try to take the square root of a negative number? That will also have to be addressed. There are several pieces of information that can potentially be returned from a single function.

There are various ways to address all of these concerns, e.g., returning error codes, passing pointers (to be used as out parameters), throwing exceptions, etc. We are going to solve the problems with tuples and structured bindings together.

First, here is the function that will take 3 inputs (a, b, c) and calculate the values using the quadratic formula:

// Error codes for quadratic formula
enum MATHERR {ERR_NONE, ERR_NEGSQRT, ERR_DIVZERO};

// A function that takes 3 doubles and returns a tuple (struct) that consists of
// the two calculated values (roots) and a (possible) error code
std::tuple<double, double, MATHERR> quadratic(double a, double b, double c)
{
    // Prevent dividing by zero
  if (a == 0)
    return {0.0, 0.0, ERR_DIVZERO}; // Construct tuple with error code and return it

    //  b^2 - 4ac
  double discriminant = b * b - 4 * a * c;

    // Prevent taking the square root of a negative number
  if (discriminant < 0)
    return {0.0, 0.0, ERR_NEGSQRT}; // Construct tuple with error code and return it

    // All safe operations now
  double pos_numerator = -b + std::sqrt(discriminant);
  double neg_numerator = -b - std::sqrt(discriminant);
  double denominator = 2 * a;

    // Return 3 pieces of information, no errors
  return {pos_numerator / denominator, neg_numerator / denominator, ERR_NONE};
}
And some code to test it:
void f36()
{
    // Setup some test values
  double a = -3.1;
  double b = 5.2;
  double c = 1.3;

  cout << "Applying quadratic formula to a, b, c (" 
       << a << ", " << b << ", " << c << ")" << endl;

    // Call the function and retrieve 3 results
  auto [root1, root2, errcode] = quadratic(a, b, c);

    // Check if there were any errors
  if (errcode == ERR_NONE)
    cout << "Roots are: " << root1 << ", " << root2 << endl;
  else if (errcode == ERR_DIVZERO)
    cout << "Divide by zero." << endl;
  else if (errcode == ERR_NEGSQRT)
    cout << "Sqrt of negative." << endl;
  else
    cout << "Unknown error." << endl; // shouldn't happen
}
Output:
Applying quadratic formula to a, b, c (-3.1, 5.2, 1.3)
Roots are: -0.220908, 1.89833
Other tests:
Applying quadratic formula to a, b, c (1, 2, 3)
Sqrt of negative.

Applying quadratic formula to a, b, c (0, 2, 3)
Divide by zero.

Applying quadratic formula to a, b, c (1, 4, 3)
Roots are: -1, -3
We could modify the test function (f36) to use selection statement (switch) initialization:
void f37()
{
    // Setup some values
  double a = -3.1;
  double b = 5.2;
  double c = 1.3;

  cout << "Applying quadratic formula to a, b, c (" 
       << a << ", " << b << ", " << c << ")" << endl;

    // Switch on the error code using select statement initialization (P0305R1)
  switch (auto [root1, root2, errcode] = quadratic(a, b, c); errcode)
  {
    case ERR_NONE:
      cout << "Roots are: " << root1 << ", " << root2 << endl;
      break;
    case ERR_DIVZERO:
      cout << "Divide by zero." << endl;
      break;
    case ERR_NEGSQRT:
      cout << "Sqrt of negative." << endl;
      break;
    default:
      cout << "Unknown error." << endl;
  }
}
This technique highlights the fact that many of the additions to C++ are not meant to stand-alone, but to be used in conjunction with other features. Structured bindings, switch initializations, and auto used by themselves don't add a lot to the language, but when used together and with other features, they are very powerful, indeed.

Generalized Attributes (N2761)

In essence, attributes are a way to give hints to the compiler about your code. Some of these hints can help the compiler detect incorrect usage of the code, suppress (safe) warnings, as well as to perform optimizations. Some attributes can be used by beginners, and others are somewhat advanced. I'm just going to show a few simple ones that will give you an idea of how they work. I expect as C++ moves into the future, more attributes will also be supported.

The concept of attributes has been around for a while, but has never been standardized. This means that each compiler had its own way of doing things. One compiler's syntax may be incompatible with another compiler's syntax. Now, C++ has standardized (some of) them to make writing portable code much easier.

Example #1: Ignoring the return value from a function. (Preventing simple mistakes.)

Many of you probably remember using printf to send text output to the display when programming in C (and C++). However, how many of you have ever used the return value from printf? I'd argue that many people don't even know what is returned. History has shown me that most students either a) don't know it returns anything or b) think that printf returns an error code of some sort. Actually, it returns the number of characters that were printed. In almost every use of printf, we don't care about the return value, so we simply ignore it, and this is all fine, safe, and legal.

However, for some functions, if you ignore the return value, the results can be catastrophic. Take for example malloc, which dynamically allocates memory and returns a pointer to that memory. If you ignore the returned pointer, then you have a memory leak. There is absolutely no way around that:

Correct usage
(safe)
Incorrect usage
(unsafe)
char *p = (char*)malloc(128); // allocate 128 bytes
// use the memory ...
free(p); // release the memory
malloc(128); // allocate 128 bytes
// Can't use the memory
// Can't free the memory (leak)

Ignoring the return from malloc is always a problem and should not be allowed to happen. (Actually, some compilers will actually warn you about this, but they are not required to.) When using any version of the g++ compiler, this is the warning that is emitted for the code on the right above (with -O enabled):
warning: ignoring return value of 'void* malloc(size_t)', declared
         with attribute warn_unused_result [-Wunused-result]
  537 |   malloc(128); // allocate 128 bytes
      |   ~~~~~~^~~~~
Granted, this is a contrived example, but a similar example below is something everyone does at some point.

Here's a concrete example: Anyone who has every written a linked-list structure knows that they often have to dynamically allocate memory for the nodes in the list and may create a helper function to do so:

Node structureHelper function
// Node for a singly linked list
struct Node
{
  int data;   // arbitrary data in the node
  Node *next; // next node in the list
};
// helper function to create a Node (no error handling)
Node *MakeNode(int value)
{
  Node *node = new Node; // allocate memory
  node->data = value;    // assign the data
  node->next = nullptr;  // set next to NULL

  return node; // return memory to the caller
}

Typical use:

Typical use (safe):Incorrect use (unsafe):
  // call helper to allocate node  
Node *p = MakeNode(42);

  // ...

delete p; // done with the node
  // call helper to allocate node  
  // but ignore the returned value  
  // (memory leak)  
MakeNode(42);

The above incorrect code will cause a memory leak. You can say, Yeah, but I would never make such a silly mistake!, which of course has been said countless times by programmers around the world! It is clearly a mistake and it would be nice if a compiler could catch it. Well, now there is a standard way of catching such a mistake by using attributes:
// helper function to create a Node (no error handling)
[[nodiscard]] Node *MakeNode(int value)
{
  Node *node = new Node; // allocate memory
  node->data = value;    // assign the data
  node->next = nullptr;  // set next to NULL

  return node; // return memory to the caller
}
By "tagging" the function with the [[nodiscard]] attribute, it tells the compiler to issue a warning if the caller ignores the return value. This can prevent silly mistakes like the one above from happening. So this code:
MakeNode(42); // Ignore important return value  
will emit a warning similar to this (from gcc):
warning: ignoring return value of 'Node* MakeNode(int)', declared with attribute nodiscard [-Wunused-result]
   MakeNode(42);
   ~~~~~~~~^~~~
note: declared here
 [[nodiscard]] Node *MakeNode(int value)
                     ^~~~~~~~

Example #2: Falling through a case in a switch statement. (Suppressing unwanted warnings.)

Many new C++ programmers forget to add a break statement in their switch statements and some compilers will warn about that because this is generally not what they wanted. However, sometimes it is exactly what the programmer intended and now there is an attribute that will suppress that warning:

Warnings emitted:Warnings suppressed:
switch (year)
{
  case 1:
    freshman++;
  case 2: 
    sophomore++;
    printf("Found lower division student.\n");
    break;
  case 3: 
    junior++;
  case 4: 
    senior++;
    printf("Found upper division student\n");
    break;
  default:
    printf("Invalid year\n");
    break;
}
switch (year)
{
  case 1:
    freshman++;
    [[ fallthrough ]]; // suppress fall through warning
  case 2: 
    sophomore++;
    printf("Found lower division student.\n");
    break;
  case 3: 
    junior++;
    [[ fallthrough ]]; // suppress fall through warning
  case 4: 
    senior++;
    printf("Found upper division student\n");
    break;
  default:
    printf("Invalid year\n");
    break;
}

These are the warnings emitted from the code on the left (from gcc):
warning: this statement may fall through [-Wimplicit-fallthrough=]
       freshman++;
       ~~~~~~~~^~
note: here
     case 2:
     ^~~~
warning: this statement may fall through [-Wimplicit-fallthrough=]
       junior++;
       ~~~~~~^~
note: here
     case 4:
     ^~~~
Note that if the case is empty, no warning will be emitted so the attribute is unecessary (with gcc):
switch (year)
{
  case 1: // No warning
  case 2: 
    lower++;
    printf("Found lower division student.\n");
    break;
  case 3: // No warning
  case 4: 
    upper++;
    printf("Found upper division student\n");
    break;
  default:
    printf("Invalid year\n");
    break;
}
This attribute is especially helpful in expressing the actual intent of the programmer. You no longer have to second-guess the code and wonder if the programmer really wanted the code to fall through or not. With the attribute in place, the intent is clear.

These two attributes are just two of several that been added since C++11. This should give you some insight into what they can be used for. I suspect that we will see many more to come in the not-so-distant future.

Read more about attributes below:

Stricter Expression Evaluation Order (P0145R3)

All C++ programmers are familiar with operator precedence. Operators also have an associativity property and an order-of-evaluation property. However, most operators do not specify the order in which their operands are evaluated. (Two notable exceptions are logical AND, &&, and logical OR, ||.)

For example, given the program below, the results are unspecified. Different compilers may give different results.

int f1()
{
  cout << "f1" << endl;
  return 1;
}

int f2()
{
  cout << "f2" << endl;
  return 2;
}

int f3()
{
  cout << "f3" << endl;
  return 3;
}
int main()
{
    // add only
  int x = f1() + f2() + f3();   
  cout << "x is " << x << endl;

    // add and multiply
  int y = f1() + f2() * f3();
  cout << "y is " << y << endl;

  return 0;
}
Compiler #1:
f1
f2
f3
x is 6
f1
f2
f3
y is 7
Compiler #2:
f1
f2
f3
x is 6
f2
f3
f1
y is 7
In all cases, the values of x and y will be correct. However, the order in which the functions are called is not specified. Compilers are free to evaluate (call) them in any order they wish. This is so compilers have the ability to optimize the runtime behavior.

With C++17, some operators are now required to evaluate their operands in a specified order, resulting in deterministic output from all compilers. One of those operators is the insertion (a.ka. output) operator: <<.

For example, given the functions above and this code:

int main()
{
    // What is the output?
  cout << f1() << f2() << f3() << endl;

  return 0;
}
Output #1:
f3
f2
f1
123
Output #2:
f1
1f2
2f3
3
You can see that with output #1, the functions were called in reverse order, yet the output from the statement in main was correct: 123. With output #2, the functions were called in the specified order and the output was also in the correct order, albeit interleaved from the output of the functions.

Now, with C++17, all compilers will output like output #2. Incidentally, the compilers that I tested gave these outputs:

Compiler/Output #1Compiler/Output #2
GNU g++ 4.8, 5, and 6
MS VS 12
MS VS 14
MS VS 19 (with default: c++14)
GNU g++ 7, 8, and 9
Clang 3.5, 3.8, 8
MS VS 19 (with /std:c++17)

I actually "discovered" this new behavior by accident when teaching a freshman C++ programming course. I was using this code (not the exact code, but it demonstrates the concept):
int main()
{
  try 
  {
    cout << "Value is: " << somefn() << endl;
  }
  catch (int)
  {
    cout << "Exception thrown" << endl;
  }

  return 0;
}
// This function may throw an exception
int somefn()
{
    // Do something here ...
    
    // If something goes wrong...
  throw 5;

    // Everything is fine
  return 5;
}
If nothing goes wrong, all compilers output:
Value is: 5
If something goes wrong:

Output from pre-C++17 compiler:
Exception thrown
Output from C++17-compliant compiler:
Value is: Exception thrown
The older compiler evaluated (called) somefn first, which threw an exception and didn't print out anything. The newer version (C++17-compliant) of the same compiler evaluated the operands of the insertion operator from left-to-right giving the output shown.

Notes:

References

This was just an introduction to some of the new features of the C++ language meant for Everyday C++ Programmers™. If you want to learn more, here are a few places to start:

Compiler support for C++:

Books:

Other resources