Подтвердить что ты не робот

Каковы варианты использования структурированных привязок?

Стандарт С++ 17 представляет новую функцию структурированные привязки, которая изначально была предложенный в 2015 году, и синтаксическое появление которого в дальнейшем обсуждалось .

Некоторые из них для них приходят на ум, как только вы просматриваете документацию.

Разложение агрегатов

Объявите кортеж:

std::tuple<int, std::string> t(42, "foo");

Именованные элементарные копии могут быть легко получены с помощью структурированных привязок в одной строке:

auto [i, s] = t;

что эквивалентно:

auto i = std::get<0>(t);
auto s = std::get<1>(t);

или

int i;
std::string s;
std::tie(i, s) = t;

Ссылки на элементы кортежа также могут быть получены безболезненно:

auto& [ir, sr] = t;
const auto& [icr, scr] = t;

Итак, мы можем делать с массивами или структурами/классами, все члены которых являются общедоступными.

Множественные возвращаемые значения

Удобный способ получить несколько возвращаемых значений из функции сразу следует из приведенного выше.

Что еще?

Можете ли вы предоставить некоторые другие, возможно, менее очевидные варианты использования структурированных привязок? Как еще они могут улучшить читаемость или даже производительность кода на С++?

Примечания

Как отмечалось в комментариях, в текущей реализации структурированных привязок отсутствуют некоторые функции. Они непеременные и их синтаксис не позволяет явно пропустить агрегированные элементы. Здесь можно найти дискуссию о вариативности.

4b9b3361

Ответ 1

Можете ли вы предоставить некоторые другие, возможно, менее очевидные варианты использования структурированных привязок? Как еще они могут улучшить читаемость или даже производительность кода на С++?

В общем, вы можете использовать его (скажем), распаковать структуру и заполнить из нее набор переменных:

struct S { int x = 0; int y = 1; };

int main() {
    S s{};
    auto [ x, y ] = s;
    (void)x, void(y);
}

Другим способом было бы:

struct S { int x = 0; int y = 1; };

int main() {
    S s{};
    auto x = s.x;
    auto y = s.y;
    (void)x, void(y);
}

То же самое можно сделать с массивами:

int main() {
    const int a[2] = { 0, 1 };
    auto [ x, y ] = a;
    (void)x, void(y);
}

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


Еще один хороший пример, упомянутый в комментариях к ответу @TobiasRibizel, - это возможность итерации через контейнеры и легко распаковать содержимое.
В качестве примера, основанного на std::map:

#include <map>
#include <iostream>

int main() {
    std::map<int, int> m = {{ 0, 1 }, { 2, 3 }};
    for(auto &[key, value]: m) {
        std::cout << key << ": " << value << std::endl;
    }
}

Ответ 2

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

Их можно использовать для реализации get<N> для structs - см. magic_get автоматически сгенерированный core17_generated.hpp. Это полезно, потому что оно обеспечивает примитивную форму статического отражения (например, перебирает все элементы struct).

Ответ 3

Не имея доказательств обратного, я думаю, что Structured Bindings - это просто средство для работы с устаревшим API. IMHO, API, которые требуют SB, должны быть исправлены.

Итак, вместо

auto p = map.equal_range(k);
for (auto it = p.first; it != p.second; ++it)
    doSomethingWith(it->first, it->second);

мы должны написать

for (auto &e : map.equal_range(k))
    doSomethingWith(e.key, e.value);

Вместо

auto r = map.insert({k, v});
if (!r.second)
    *r.first = v;

мы должны написать

auto r = map.insert({k, v});
if (!r)
    r = v;

и др.

Конечно, кто-то найдет умное использование в какой-то момент, но для меня, спустя год, узнав о них, они все еще остаются неразгаданными. Особенно поскольку эта статья является соавтором Бьярне, который обычно не известен тем, что внедряет функции, которые имеют такую ​​узкую применимость.