The C++14 standard is finally set. It is a less radical change than C++11 adding a number of refinements that did not make it into the older standard. The Working Draft N3797 addresses most of the changes.

Bjarne Stroustrup, creator of C++ had a hand in things and gave us some feedback on C++14 (see “Bjarne Stroustrup Talks About C++14”). Bjarne is in the Electronic Design Engineering Hall of Fame in 2013 (see “Gallery: 2013 Engineering Hall Of Fame). He had a Q&A on August 20th at the Google+ C++ Community.

C++11 added a lot of features that were generally useful and handy for embedded developers. The same is true for C++14. They are sometimes subtle they can make a big difference when creating safe and reliable applications as well as dealing with low level interfaces such as microcontroller registers.

There are lots of horror stories about embedded applications that failed because of using the wrong units or performing operations like adding two incompatible units. C++14 would allow the compiler to catch these errors. It can also lead to more readable code.

Auto Everywhere

The auto keyword was a key addition in C++11. It provided a way for the compiler to determine the data type of a definition instead of having it explicitly set. This worked with variable initialization. This includes for-loop definitions like this:

for (auto i = myobj.start() ; i != myobj.end(); ++ i)

C++14 now lets programmers use auto to specify the return type of a function.

auto double (int n)
{
  return n + n;
}

The feature has been extended to lambdas, nameless functions added in C++11. Lambda capture variables can also be initialized in C++14. This saves performing the operation externally. This example highlights the new auto and lambda initialization features.

auto delta_timer = [start = system_clock::now()] { return system_clock::now() - start; };

More Initialization

Initialization using auto is handy but there are additional features available with C++14. Aggregate initialization is one. It works for in-class members.

Standard User Defined Literals

C++11 introduced the idea of user defined literals. This allowed data types and functions to be defined so that values can have units attached to them although there are other uses. This Weight class example shows how this can be done although the definition is incomplete and it is an ideal candidate for a template.

class Weight {
  double rawWeight;
  Weight(double initial) { rawWeight = initial ; }
public:
  class DoubleIsWeight{}; // a tag
  explicit constexpr Weight(DoubleIsWeight, double wgt) : rawWeight{wgt} {}
  Weight operator+(const Weight& w) { return rawWeight + w.rawWeight ; }
  Weight operator-(const Weight& w) { return rawWeight - w.rawWeight ; }
  bool operator>(const Weight& w) { return rawWeight > w.rawWeight ; }
};

constexpr Weight operator "" _kg( long double wgt ) {
  return Weight{Weight::DoubleIsWeight{}, static_cast<double>(wgt)};
}

constexpr Weight operator "" _lb( long double wgt ) {
  return Weight{Weight::DoubleIsWeight{}, static_cast<double>(wgt * 0.45359237)};
}

int main() {
  Weight a = 10.2_kg;
  Weight b = 20.0_lb;
  Weight c = a + b ;
  cout << (c > 0.0_kg ? "!!!Hello World!!!" : "x") << endl;
  return 0;
}

Note that 20_lb would not work at this point since the argument is a long double, not an integer. Of course, additional definitions could handle the conversion.

In any case, changes to the Standard Template Library (STL) now take advantage of this feature. These include a string type for std::basic_strings and time literals for std:chrono::duration. This allows statements like these to work.

string my_string = "hello world"s;
chrono::duration my_time = 1h + 2min + 3s + 4ms + 5us + 6ns ;

The "s" literals do not conflict as one is applicable to string literals while the other applies to integers.

The constexpr keyword was used in the prior example. It provides a compile-time function expression. C++14 relaxes the restrictions originally set in C++11 where the function could only return an expression result. It is now possible to use features such as conditional branching and for range-based expressions.

Readable Literals

Embedded programmers will like the new binary literals. No more converting hex constants when dealing with I/O ports. Binary literals start with 0b or 0B and are followed by a bunch of 1’s and 0’s. There is also a change to make the values more readable.

auto a1 = 0b1011111101011011;
auto a2 = 0b1011'1111'0101'1011;

The apostrophe acts as a digit separator. The placement is arbitrary. Need octal spacing? No problem. Need a binary constant for a register? That works too.

The digit separator works with any numeric constant. This can be handy for other common constants.

auto color = 0x00'23'ff;
auto mac_address = 0x00'23'44'23'ca'ff;
auto not_an_ipv4_address = 111'
22'33'44; // this is really 111223344 not 111.22.33.44

The last one highlights how the approach is not applicable to all constant encodings. Of course, user defined literal might be more applicable since a constexpr function can parse a string and even flag syntax errors while delivering a typed result.

C++11 delivered a lot more but C++14 improves on it but in a less drastic fashion.