New feature of C++17 (2) -- Init statement for if/switch initialization

Keywords: C++

1 Introduction

C++17 introduces a new version of if/switch statement form, if (init; condition) and switch (init; condition), which can declare variables and initialize them directly in if and switch statements.
In the case of if, before C++17, we might write as follows:

{
    auto val = GetValue();
    if(condition(val))
    {
        // some codes if is true
    }
    else
    {
        // some codes if is false
    }
}

It can be seen that val is in a separate scope, which exposes val to effects other than lf. In C++17, you can write as follows:

if(auto val = getValue(); condition(val))
{
    // some codes if is true
}
else
{
    // some codes if is false
}

In this way, val is only visible in if and else and will not leak into other scopes.
Note: val, a variable declared and initialized in if, is also valid in else.

2 init-state tasting

Here are just a few small attempts at this new feature, some tricks.

Case 1: Addressing Naming Difficulties

This part mainly uses the C++ 17init-state feature to reduce the naming of new variables, and mainly takes advantage of the fact that variables declared in if/else and switch have smaller scopes.
Assuming that a substring is found in a string, we can write as follows:

#include <iostream>
#include <string>

using namespace std;

int main()
{
    const string myString = "My hello world string";
    const auto it = myString.find("hello");
    if(it != string::npos)
    {
        cout << it << " - Hello\n";
    }
    // you have to make another name different from it.
    const auto it2 = myString.find("world");
    if(it2 != string::npos)
    {
        cout << it2 << " - World\n";
    }
    return 0;
}

We can declare and define a new variable it2, or use it for a separate scope as follows:

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

But in C++17, the new if-state syntax makes such scopes more concise:

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

As mentioned earlier, variables in the if statement are still visible in else:

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

Case 2: if-initializer+structured binding

In addition, structured bindings can also be used in the new if-state grammar:

// better together: structured bindings + if initializer
if (auto [iter, succeeded] = mymap.insert(value); succeeded) {
    use(iter);  // ok
    // ...
}   // iter and succeeded are destroyed here

Here is a complete example:

#include <iostream>
#include <string>
#include <set>

using namespace std;
using mySet = set<pair<string,int>>;
int main()
{
    mySet set1;
    pair<string,int> itemsToAdd[3]{{"hello",1},{"world",1},{"world",2}};
    for(auto &p : itemsToAdd)
    {
        // if-initializer + structured binding
        if(const auto [iter,inserted] = set1.insert(p);inserted)
        {
            cout << "Value(" << iter->first << ", " << iter->second << ") was inserted\n";
        }
        else
        {
            cout << "Value(" << iter->first << ", " << iter->second << ") was not inserted\n";
        }
    }
    return 0;
}

Reference

[1]7 Features of C++17 that will simplify your code

Posted by ashokkumar on Sun, 23 Dec 2018 18:33:05 -0800