cout << "-----\n";
7. Можно сделать лучше. Даже не зная типов аргументов функции print_student
std::apply
. Она принимает указатель на функцию или объект функции и кортеж, а затем apply(print_student, john);
cout << " \n";
8. Конечно, все это прекрасно работает и в цикле:
for (const auto &args : arguments_for_later) {
apply(print_student, args);
}
cout << "-----\n";
}
9. Компиляция и запуск программы покажут, что работают оба подхода, как мы и предполагали:
$ ./apply_functions_on_tuples
Student "John Doe", ID: 123, GPA: 3.7
-----
Student "John Doe", ID: 234, GPA: 3.7
Student "Billy Foo", ID: 345, GPA: 4
Student "Cathy Bar", ID: 456, GPA: 3.5
-----
Student "John Doe", ID: 123, GPA: 3.7
-----
Student "John Doe", ID: 234, GPA: 3.7
Student "Billy Foo", ID: 345, GPA: 4
Student "Cathy Bar", ID: 456, GPA: 3.5
-----
Как это работает
Функция std::apply
Допустим, у нас есть кортеж t
(123, "abc"s, 456.0)
. Он имеет тип tuple
. Вдобавок предположим, что у нас есть функция f
с сигнатурой int f(int, string, double)
(типы также могут быть ссылками).Затем можно написать конструкцию x = apply(f, t)
x = f(123, "abc"s, 456.0)
. Метод apply
даже не возвращает результат работы функции f
. Быстрое создание структур данных с помощью std::tuple
Взглянем на простой пример использования кортежей, с которым мы уже сталкивались. Мы можем определить следующую структуру, чтобы просто объединить некоторые переменные в одну сущность:
struct Foo {
int a;
string b;
float c;
};
Вместо того чтобы определять структуру, как было сделано в предыдущем примере, можно также определить кортеж:
using Foo = tuple
Получить доступ к его элементам можно по порядковому номеру типа из списка типов. Для получения доступа к первому члену кортежа t
std::get<0>(t);
для получения доступа ко второму члену — std::get<1>
и т.д. Если порядковый номер слишком велик, то компилятор безопасно сгенерирует ошибку.На протяжении этой книги мы уже использовали возможности декомпозиции C++17 для кортежей. Она позволяет быстро разбить кортеж на элементы, просто написав auto [a,b,c] = some_tuple
Композиция и декомпозиция отдельных структур данных — не единственная возможность, которую предоставляют кортежи. Мы также можем конкатенировать или разбивать кортежи. В этом разделе мы поэкспериментируем с данными функциями, чтобы узнать, как они работают.
Как это делается
В этом примере мы напишем программу, которая может динамически вывести на экран любой кортеж. Вдобавок напишем функцию, способную
1. Сначала включим несколько заголовочных файлов, а затем объявим об использовании пространства имен std
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
2. Поскольку мы будем работать с кортежами, было бы интересно отобразить их содержимое. Поэтому сейчас реализуем очень обобщенную функцию, которая может выводить на экран любые кортежи. Функция принимает ссылку на поток вывода os
v
, а остальные поместили в наборе параметров vs...
:template
void print_args(ostream &os, const T &v, const Ts &. vs)
{
os << v;
3. Если в наборе параметров еще есть аргументы, то они выводятся на экран, притом их разделяет символ ",
initializer_list
. Мы говорили о нем в главе 4. (void)initializer_list
}