Полезные новации С++17. Инициализирующее выражение для if/switch.

Новая версия выражений  if и switch для С++:

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


Ранее мы должны были писать так:

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

Фигурные скобки введены сознательно, дабы ограничить область видимости val и предотвратить его "утечку" в окружающее выражение.

Теперь мы можем написать:

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

val теперь видимо только внутри if и else выражений ("утечка" исключена). condition может быть любым условием - не только для случая, когда val имеет булево значение.

Почему это полезно?

Допустим мы хотим найти что-то в строке:

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"

Мы должны использовать различные имена для итераторов, либо замкнуть их в разные области видимости:

{ 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" }

Новое выражение 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";

Как упоминалось выше, переменная , определённая в выражении if также видима в блоке else. Таким образом, можно написать:

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

Итак - работающий пример:

#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";
}

Особенно мне понравилась возможность использования этого вместе со структурированным связыванием (что такое 'structured binding' надо будет рассказать отдельно):

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


Ещё рабочий пример:

#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"; 
}
}

Поддержка:

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

Подробности:

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0305r1.html
https://www.youtube.com/watch?v=AiXU5EuLZgc&feature=youtu.be
https://herbsutter.com/2016/06/30/trip-report-summer-iso-c-standards-meeting-oulu/
























Комментарии

Популярные сообщения из этого блога

Полезные новации С++17. Выражения свертки (Fold expressions)

Перегрузка и специализация шаблонных функций.

Поддержка декомпозиции при объявлении (structural bindings) для классов