C++ is a language that is about as old as I am. Seriously. It was first called “C++” in December 1983, two months after I was born, although it had been in the works for a few years before that. So it’s an old language, but that doesn’t mean it’s obsolete or dead. No, far from it. In fact, the latest update to the language, called C++17, is scheduled for release in—you guessed it—2017, i.e., next year.
Why is that important? Well, if you know the history of C++, you know the story of its standardization. The first true standard only came out in 1998, and it was only then that all the template goodness was finally available to all. (Let’s all try to imagine Visual C++ 6 never happened.) Five years later, in 2003, we got a slight update that didn’t do much more than fill in a few blanks. Really, for over a decade, C++ was essentially frozen in time, and that was a problem. It missed the dot-com boom and the Java explosion, and the growth of the Internet and dynamic scripting languages seemed to relegate it to the dreaded “legacy” role.
Finally, after what seemed like an eternity, C++11 came about. (It was so delayed that its original codename was C++0x, because everyone thought it’d be out before 2010.) And it was amazing. It was such a revolution that coders speak of two different languages: C++ and Modern C++. Three years later, C++14 added in a few new bits, but it was more evolutionary than revolutionary.
What C++ did, though, was prepare programmers for a faster release schedule. Now, we’ve seen how disastrous that has been for projects like Firefox, but hear them out. Instead of waiting forever for all the dust to settle and a new language standard to form, they want to do things differently, and C++17 will be their first shot.
C++ is now built on a model that isn’t too different from version control systems. There’s a stable trunk (standard C++, of whatever vintage), and that’s the “main” language. Individual parts are built in what they call Technical Specifications, which are basically like Git branches. There’s one for the standard library, networking, filesystem support, and so on. These are largely independent of the standard, at least in development terms. When they’re mature enough, they’ll get merged into the next iteration of Standard C++. (Supposedly, that’ll be in 2019, but 2020 is far more likely.) But compilers are allowed—required, actually, as the language needs implementations before standardization—to support some of these early; these go under std::experimental
until they’ve cooked long enough.
So C++17 is not exactly the complete overhaul of C++11, but neither is it the incremental improvement of C++14. It stands between the two, but it sets the stage for a future more in line with, say, JavaScript.
New features
I have neither the time nor the knowledge to go through each new feature added to C++17. Instead, I’ll touch on those I feel are most important and interesting. Some of these are available in current compilers. Others are in the planning stages. None of that matters as long as we stay in the realm of theory.
Fold expressions
Okay, I don’t care much for Haskell, but these look pretty cool. They take a parameter pack and reduce or fold it using some sort of operation, in the same way as Haskell’s foldl
and foldr
. Most of the binary operators can be used, which gives us some nifty effects. Here are a few basic examples:
// Returns true if all arguments are true
template <typename... Args>
bool all(Args... args) { return (... && args); }
// Returns true if *any* arguments is true
template <typename... Args>
bool any(Args... args) { return (... || args); }
// Returns the sum of all arguments
template <typename... Args>
int sum(Args... args) { return (args + ... + 0); }
// Prints all values to cout (name references JS)
template <typename... Args>
void console_log(Args&&... args)
{ (std::cout << ... << args) << '\n'; }
Yeah, implementing any
, all
, and even a variadic logging function can now be done in one line. And any functional fan can tell you that’s only the beginning.
Structured bindings
Tuples were a nice addition to C++11, except that they’re not terribly useful. C++, remember, uses static typing, and the way tuples were added made that all too evident. But then there’s the library function std::tie
. As its name suggests, one of its uses is to “wire up” a connection between a tuple and free variables. That can be used for a kind of destructuring assignment, as found in Python. But C++17 is going beyond that by giving this style of value binding its own syntax:
using Point3D = tuple<double, double, double>;
// This function gives us a point tuple...
Point3D doSomething() { /* ... */ }
// ...but we want individual X/Y/Z
// With std::tie, we have to do this:
//
// double x, y, z;
// std::tie(x,y,z) = doSomething();
// But C++17 will let us do it this way:
auto [x,y,z] = doSomething();
Even better: this works with arrays and pairs, and it’s a straight shot from there to any other kind of object. It’s a win all around, if you ask me.
if
initializers
This one’s less “Wow!” than “Finally!”, but it’s good to have. With C++17, you’ll be able to declare a variable inside the conditional of an if
or switch
, just like you’ve been able to do with (old-style) for
loops for decades:
if (int value; value >= 0)
{
// do stuff for positive/zero values
}
else
{
// do stuff for negative values
// Note: value is still in scope!
}
Again, not that big a deal, but anything that makes an overcomplicated language more consistent is for the best.
constexpr if
This was one of the later additions to the standard, and it doesn’t look like much, but it could be huge. If you’ve paid any attention to C++ at all in this decade, you know it now has a lot of compile-time functionality. Really, C++ is two separate languages at this point, the one you run and the one that runs while you compile.
That’s all thanks to templates, but there’s one big problem. Namely, you can’t use the run-time language features (like, say, if
) based on information known only to the compile-time half. Languages like D solve this with “static” versions of these constructs, and C++17 gives us something like that with the constexpr if
:
template<typename H, typename... Ts>
void f(H&& h, Ts&& ...ts)
{
doItTo(h);
// Now, we need to doItTo all of the ts,
// but what if there aren't any?
// That's where constexpr if helps.
if constexpr(sizeof...(ts) > 0)
doItTo(ts...);
}
If implemented properly (and I trust that they’ll be able to do that), this will get rid of a ton of template metaprogrammming overhead. For simple uses, it may be able to replace std::enable_if
and tag dispatch, and novice C++ programmers will never need to learn how to pronounce SFINAE.
Continuation
Those are some of my favorite features that are on the table for C++17. In the next post, we’ll look at the changes to the standard library.
One thought on “First glance: C++17, part 1”