Click here to Skip to main content
13,626,436 members
Click here to Skip to main content
Add your own
alternative version

Tagged as

Stats

10.9K views
29 bookmarked
Posted 3 Jan 2018
Licenced CPOL

From C++ 11 to C++ 17: A Walkthrough

, 5 Jan 2018
Rate this:
Please Sign up or sign in to vote.
The most appealing (to me!) new C++ features.

Introduction

This small article contains 20 features since C++ 11 and up to C++ 17 that appealed to me, so I present them to you, along with some nasty comments. Happy reading. This article will be updated constantly.

Background

Yes, assume full C++ 11 knowledge. This is not a beginner's article. 

The features

New and updated literals


// C++ 14 Binary literals
int a = 0b111; // a = 7

// C++ 14 Prefixes
auto str = "hello"s; // auto deduces string
auto dur = 60s;      // auto deduces chrono::seconds
auto z   = 1i;       // auto deduces complex<double>

+1, although I would somewhat prefer to not excessively use auto everywhere.

 

Digit separators


// C++ 14
int a = 1'000'000; 

+1. Makes reading large numbers (especially 64 bit pointers) easier.

 

Variable templates


// C++ 14
template <typename T> T pi = (T)3.141592;
double x = sin(2.0*440.0*pi<double>*0.01); // specializes pi as double
float perimeter = 2.0f*pi<float>*radius; // specializes pi as float

=0. I haven't really found anything useful for it yet.  Templating a function or a class OK - you want to use it with numerous types. Templating a variable means that I have the same name for actually different variables - ouch. Actually, the only example I 've found online is the pi version.

 

Function return auto deduction


// C++ 14
auto foo(int j,int x)
{
    return j + x; // "auto" -> "int";
}

auto boo();

auto tu() // better than tuple<int,int,int> tu()
{
    return make_tuple<int,int,int>(5,6,7);
}

int main()
{
    auto t = tu(); // t = tuple(5,6,7)
    int a = foo(5,6); // OK
    int b = boo(); // Error
}

+1. Mostly useful for lengthy-types like the tuple above. If there are multiple return statements, all of them must deduce the same type. Since this is a single-pass, the deduction must be available when it is needed. For example, the int b = boo() line will fail because boo hasn't been defined yet, even if the line suggests an int-value. Defining the function in another TU, or even in the same TU but below that code will fail.

 

Related lambdas


// C++ 14
auto lambda = [](auto x, auto y) {return x + y;};

+1. Auto enables you to type less.

Namespace nesting


// C++ 11
namespace A 
{
    namespace B
    {
        namespace C
        {
        }
    }
}

// C++ 17
namespace A::B::C
{
}

+1. Significantly less typing.

 

Structure binding


tuple<int,float,char> x() { return make_tuple<int,float,char>(5,5.2f,'c'); }

// C++ 11
int a;
float b;
char c;
std::tie(a,b,c) = x();

// C++ 17
auto [a,b,c] = x();

+1. It also works in structures. The problem is that you can't use std::ignore, like in the old tie.

 

std::optional


// C++ 17
using namespace std;
optional<string> foo()
{
    if (something)
       return "Hello";
    return {};
}

int main()
{
    auto rv = foo();
    if (rv) 
    {
         // We have a value, rv.value();
    }
    rv.value_or("dada"); // Either the value, or "dada"
}

+1. Allows a "nothing" return value to be returned while providing a catchall case with value_or. HOWEVER, this does not work as intended:

// C++ 17
using namespace std; 
optional<int> foo(int x) 
{ 
if (x == 1)
   return 5; 
}

Now I still get a compiler warning, and probably an undefined-behaviour std::optional. When there is a non returning path, return {} should be implied (Yes I 've proposed it and yes they all disagree with me. Who cares :))

std::any


// C++ 17
using namespace std;
any foo()
{
    string h("hello");
    return any(h);
}

int main()
{
    try 
    {
        auto r = any_cast<string>(foo());
    }
    catch(...)
    {
    }
}

+1 I do not like it much,  but I have found a nice trick with it.

 

std::variant


// C++ 11
union A
{
    int a;
    float b;
    char c;
};

A x;
x.a = 5; 
float b = x.b; 

// C++ 17
using namespace std;
variant<int,float,char> x;
x = 5; // now contains int
int i = std::get<int>(v); // i = 5;
std::get<float>(v); // Throws

=0, std::variant is not a normal union, but a type-safe union, because it throws when you try to access the non-current type. However the point of the old-type unions is to share memory without types (consider the old x86 union ax { struct {char al,char ah};  short ax; } ).  I 'm not very sure of a useful case scenario.

Fold expressions


// C++ 11 add numbers
template <typename T>
T add(T t) { return t; }

template <typename T, typename... Many>
T add(T t, Many... many) {
  return t + add(many...);
}


// C++ 17 fold expressions
template <typename T, typename ... Many>
T add(T t, Many... many)
{
   return (t + ... + many);
}


// ----
int main()
{
  auto r = add(1,2,3,4,5,6,7,8,9,10); // r = 55, but in C++ 17 method we only need one function.
}

+100. No comments. The idea is to combine the ellipsis with one of the operators to produce a non-comma expansion of the pack.

 

#if has_include


// C++ 17
#if __has_include(<string>)
// Assume <string> has been included
#else
#endif

=0. It's OK, generalizes old #pragma once  and #IFNDEF _STRING_H stuff

 

template <auto>


// C++ 17
template <auto value> void foo() { }
foo<3>();               // deduces int

+1, autos anywhere :)

 

Some new attributes


// C++ 14
// [[deprecated("reason")]]

void [[deprecated("This function is not safe")]] foo ()
{
}


// C++ 17
// [[fallthrough]]
// Notifies the compiler that a lack of break is intentional

switch(a)
{
    case 1:
       test(); // Warning issued, did the programmer forget the break statement?
    case 2: 
       test2();
       [[fallthrough]]; // No warning, the lack of break was intentional
    case 3: 
       ////
}


// [[nodiscard]] 
// Issues a warning when a return value of a function is discarded

[[nodiscard]] int foo()
{
    return 1;
}

int main()
{
   foo(); // issues a warning
   int a = foo(); // not a warning now
}


// [[maybe_unused]]
int foo()
{
    [[maybe_unused]] int y;
    // No warning later if y is not used. Something like UNREFERENCED_PARAMETER() macro
}

+1, they are nice standarizations for older pragma's.

if and switch init before conditions


// C++ 11
int val = foo();
if (val == 1)
{
}

// C++ 17
if (int val = foo() ; val == 1)
{
}

+1, the difference is that the variable's scope is inside the if only. 

 

inline variables


// C++ 17
inline int x = 5;
​​​​​

+1000, now you can include also variables in .h files without problem. It can be included as many times as needed and it's only defined once.

 

Auto deduction from initializer lists


 

// C++ 11
std::initializer_list<int> x1 = { 1, 2 };

// C++ 17
auto x1 = { 1, 2 }; // automatically std::initializer_list<int>

+1. Nice auto again. 

 

 

constructor template deduction


// C++ 11
auto p = std::pair<double,int>(5.0,0);

// C++ 17
auto p = std::pair(5.0,0); // deduces double,int

+1000, it was about time.

 

Exception specifications are part of the type 


// C++ 11
void (*p)() throw(int); // a function pointer to a function that throws an int
void (**pp)() throw() = &p;   // a function pointer to a function that does not throw

+1. In C++ 17, the above is an error. The exception specification throw(int) is now part of the type.

 

And finally.....

string_view


// C++ 17
using namespace std;

string a = "hello there";
// a uses dynamic memory 

string_view largeStringView{a.c_str(), a.size()};

+1000. A string_view gives us all the benefits of std::string but on a string that is already owned ( either be another string or a char array). Therefore, it can be used in non-mutable situations (like comparisons or substrings).

 

Acknowledgments

  • http://www.bfilipek.com/2017/01/cpp17features.html#lambda-capture-of-this
  • https://en.wikipedia.org/wiki/C%2B%2B14
  • https://en.wikipedia.org/wiki/C%2B%2B17
  • http://libcxx.llvm.org/cxx1z_status.html
  • http://clang.llvm.org/cxx_status.html#cxx17
  • https://stackoverflow.com/questions/38060436/what-are-the-new-features-in-c17

 

History
 

  • 03 - 01 - 2018 : First release, happy new year!

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Michael Chourdakis
Engineer
Greece Greece
I'm working in C++, PHP , Java, Windows, iOS and Android.

I 've a PhD in Digital Signal Processing and I specialize in Pro Audio applications.

My home page: http://www.michaelchourdakis.com

You may also be interested in...

Comments and Discussions

 
SuggestionNeat Article Pin
Paul Nader30-May-18 23:36
memberPaul Nader30-May-18 23:36 
PraiseThanks Pin
Huzifa Terkawi27-Feb-18 12:45
memberHuzifa Terkawi27-Feb-18 12:45 
GeneralNice and concise Pin
ITISAG4-Jan-18 7:44
memberITISAG4-Jan-18 7:44 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

Permalink | Advertise | Privacy | Cookies | Terms of Use | Mobile
Web03 | 2.8.180712.1 | Last Updated 5 Jan 2018
Article Copyright 2018 by Michael Chourdakis
Everything else Copyright © CodeProject, 1999-2018
Layout: fixed | fluid