7 Features of C++17 that will simplify your code

fenbf
21.8K views

Open Source Your Knowledge, Become a Contributor

Technology knowledge has to be shared and made accessible for free. Join the movement.

Create Content

Init statement for if/switch

New versions of the if and switch statements for C++:

if (init; condition) and switch (init; condition).

Previously you had to write:

{   
    auto val = GetValue();   
    if (condition(val))    
        // on success  
    else   
        // on false... 
}

Look, that val has a separate scope, without that it 'leaks' to enclosing scope.

Now you can write:

if (auto val = GetValue(); condition(val))    
    // on success  
else   
    // on false... 

val is visible only inside the if and else statements, so it doesn't 'leak.' condition might be any condition, not only if val is true/false.

Why is this useful?

Let's say you want to search for a few things in a string:

const std::string myString = "My Hello World Wow";

const auto it = myString.find("Hello");
if (it != std::string::npos)
    std::cout << it << " Hello\n"

const auto it2 = myString.find("World");
if (it2 != std::string::npos)
    std::cout << it2 << " World\n"

We have to use different names for it or enclose it with a separate scope:

{
    const auto it = myString.find("Hello");
    if (it != std::string::npos)
        std::cout << it << " Hello\n"
}

{
    const auto it = myString.find("World");
    if (it != std::string::npos)
        std::cout << it << " World\n"
}

The new if statement will make that additional scope in one line:

if (const auto it = myString.find("Hello"); it != std::string::npos)
    std::cout << it << " Hello\n";

if (const auto it = myString.find("World"); it != std::string::npos)
    std::cout << it << " World\n";

As mentioned before, the variable defined in the if statement is also visible in the else block. So you can write:

if (const auto it = myString.find("World"); it != std::string::npos)
    std::cout << it << " World\n";
else
    std::cout << it << " not found!!\n";

Working sample:

Searching strings
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#include <iostream>
#include <string>
int main()
{
const std::string myString = "Hello World";
auto it = myString.find("Hello");
if (it != std::string::npos)
std::cout << it << " Hello\n";
auto it2 = myString.find("World");
if (it2 != std::string::npos)
std::cout << it2 << " World\n";
// additional enclosing scope so 'it' doesn't 'leak'
{
auto it = myString.find("Hello");
if (it != std::string::npos)
std::cout << "Hello\n";
}
{
auto it = myString.find("World");
if (it != std::string::npos)
std::cout << "World\n";
}
// C++17 with init if:
if (const auto it = myString.find("Hello"); it != std::string::npos)
std::cout << it << " Hello\n";
if (const auto it = myString.find("World"); it != std::string::npos)
std::cout << it << " World\n";
}
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

Plus, you can use it with structured bindings (following Herb Sutter code):

// better together: structured bindings + if initializer
if (auto [iter, succeeded] = mymap.insert(value); succeeded) {
    use(iter);  // ok
    // ...
} // iter and succeeded are destroyed here
Structured bindings and init if
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <iostream>
#include <set>
#include <string>
#include <tuple>
#include <utility>
using namespace std;
int main()
{
set<pair<string, int>> mySet;
pair<string, int> itemsToAdd[3] { {"hello", 1}, { "world", 2 }, { "world", 2 } };
for (auto &p : itemsToAdd)
{
if (const auto [iter, inserted] = mySet.insert(p); inserted)
cout << "Value(" << iter->first << ", " << iter->second << ") was inserted" << "\n";
else
cout << "Value(" << iter->first << ", ...) not inserted!" << "\n";
}
}
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

More details in

GCC: 7.0, Clang: 3.9, MSVC: in VS 2017.3.

Open Source Your Knowledge: become a Contributor and help others learn. Create New Content