Полезные новации С++17. Структурированное связывание.

Вы часто работаете с кортежами?

Если нет - то, возможно, будете - прочитав нижеследующее. Не только кортежи предполагают возвращение множества значений из функции, но они также имеют специальную языковую поддержку, делающую код более легким и понятным.

Например (std::tie example):

std::set<S> mySet; S value{42, "Test", 3.14}; std::set<S>::iterator iter; bool inserted; // unpacks the return val of insert into iter and inserted std::tie(iter, inserted) = mySet.insert(value); if (inserted) std::cout << "Value was inserted\n";


Заметьте, что вам необходимо сначала объявить iter и inserted. Затем, можно использовать std::tie для создания кортежа. Переопределённый оператор присваивания кортежа может принимать пару (pair<>) значений.

С С++17:

std::set<S> mySet; S value{42, "Test", 3.14}; auto [iter, inserted] = mySet.insert(value);

 И всё! Дело в волшебных квадратных скобках!

Полный рабочий код:

#include <cstdlib>
#include <iostream>
#include <set>
#include <string>
#include <iterator>

#include <tuple>

// { autofold 
struct S {
    int n;
    std::string s;
    float d;
    bool operator<(const S& rhs) const
    {
        // compares n to rhs.n,
        // then s to rhs.s,
        // then d to rhs.d
        return std::tie(n, s, d) < std::tie(rhs.n, rhs.s, rhs.d);
    }
};
// }

int main()
{
    std::set<S> mySet;

    // pre C++17:
    {
    S value{42, "Test", 3.14};
    std::set<S>::iterator iter;
    bool inserted;

    // unpacks the return val of insert into iter and inserted
    std::tie(iter, inserted) = mySet.insert(value);

    if (inserted)
    std::cout << "Value was inserted\n";
    }

// with C++17:
    {
        S value{100, "abc", 100.0};
        const auto [iter, inserted] = mySet.insert(value);

        if (inserted)
    std::cout << "Value(" << iter->n << ", " << iter->s << ", ...) was inserted" << "\n";
    }
        
}

Структурированное связывание не ограничено кортежами, мы имеем три варианта:

1) Инициализатор является массивом:

// works with arrays: double myArray[3] = { 1.0, 2.0, 3.0 }; auto [a, b, c] = myArray;

2)  Инициализатор поддерживает std::tuple_size<> и предоставляет функцию get<N>().

auto [a, b] = myPair; // binds myPair.first/second


Другими словами, вы можете предоставить поддержку для ваших классов через добавление реализации интерфейса get<N>().

3) Тип инициализатора содержит только нестатические, открытые члены:

struct S { int x1 : 2; volatile double y1; }; S f(); const auto [ x, y ] = f();

Наиболее интересна поддержка циклов:

std::map myMap; for (const auto & [k,v] : myMap) { // k - key // v - value }

Пример:

#include <iostream>
#include <map>
#include <string>

int main()
{
const std::map<std::string, std::string> capitals{
{ "Poland", "Warsaw" },
{ "USA", "Washington" },
{ "France", "Paris" },
{ "UK", "London" },
{ "Germany", "Berlin" }
};

for (auto[key, value] : capitals)
{
std::cout << "key : " << key << ", value : " << value << std::endl;
  }

return 0;
}

Поддержка: 
GCC: 7.0, Clang: 4.0, MSVC: in VS 2017.3.

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

http://cpp-today.blogspot.ru/2017/03/structured-binding-c17-inside.html
https://skebanga.github.io/structured-bindings/








Комментарии

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

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

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

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