Structure bindings и structure matching в аргументах функции
Распаковка структур данных прямо в аргументах функции
Иногда очень хочется делать structure matching в аргументах функции.
В C++ есть передача аргументов по значению. Т.е. конструктор копирования выполняется до кода функции.
Хотелось бы делать что-то похожее на structure binding.
using Type = std::tuple<int, char, std::string>;
void foo(Type& [a, b, c]) {
std::cout << a << ' ' << b << ' ' << c << '\n';
}
Здесь type(a) == int&; type(b) == char&; type(c) = std::string&.
void foo(Type [a, b, c]) {
std::cout << a << ' ' << b << ' ' << c << '\n';
}
Здесь type(a) == int; type(b) == char; type(c) == std::string
void foo(Type&& [a, b, c]) {
std::cout << a << ' ' << b << ' ' << c << '\n';
}
Здесь type(a) == int&&; type(b) == char&&; type(c) == std::string&&
Предложение
Ввести такой синтаксис.
Почему это удобно
Вы не заводите новых имён в функции. Без этого нужно было бы писать так:
void foo(Type type) {
auto& [a, b, c] = type;
// ...
}
void foo(Type& type) {
auto& [a, b, c] = type;
// ...
}
Проблема налицо: появляется новое имя type и можно забыть написать auto&, чтобы не вызвать лишний конструктор копирования.
Это имеет смысл возможно только при наличии каких-либо других аргументов, помимо указанного пака параметров, хотя и тут выкрутиться можно. Что же касается случая, приведенного выше, то оно, начиная с C++17 решается при помощи std::apply:
void foo(int a, char b, const std::string& c) { ... }
std::tuple<int, char, std::string> tpl(...);
std::apply(foo, tpl);
Кроме того, приведенные в посте примеры сильно ограничивают типы аргументов. Так, например, не получится сделать, чтобы инты передавались по значению, а строки - по ссылке.
Для передачи по ссылке и т.д. можно подключить что-то из предыдущего предложения #447. Но тогда непонятно, как копировать и где хранить объект.
К тому же, std::apply работает только для std::tuple, а здесь предлагается реализовать это для всех типов, где есть structured binding. (в т.ч. и своих)