We are going to implement a program that packs and unpacks values to and from tuples. Then, we will see how to call functions that know nothing about tuples with values from tuples:
- First, we include a lot of headers and declare that we use the std namespace:
#include <iostream>
#include <iomanip>
#include <tuple>
#include <functional>
#include <string>
#include <list>
using namespace std;
- Let's first define a function that takes multiple parameters describing a student and prints them. A lot of legacy- or C-function interfaces look similar.:
static void print_student(size_t id, const string &name, double gpa)
{
cout << "Student " << quoted(name)
<< ", ID: " << id
<< ", GPA: " << gpa << 'n';
}
- In the actual program, we define a tuple type on the fly and fill it with meaningful student data:
int main()
{
using student = tuple<size_t, string, double>;
student john {123, "John Doe"s, 3.7};
- In order to print such an object, we can decompose it to its individual members and call print_student with those individual variables:
{
const auto &[id, name, gpa] = john;
print_student(id, name, gpa);
}
cout << "-----n";
- Let's create a whole set of students in the form of an initializer list of student tuples:
auto arguments_for_later = {
make_tuple(234, "John Doe"s, 3.7),
make_tuple(345, "Billy Foo"s, 4.0),
make_tuple(456, "Cathy Bar"s, 3.5),
};
- We can still relatively comfortably print them all, but in order to decompose the tuple, we need to care how many elements such tuples have. If we have to write such code, then we will also have to restructure it in case the function call interface changes:
for (const auto &[id, name, gpa] : arguments_for_later) {
print_student(id, name, gpa);
}
cout << "-----n";
- We can do better. Without even knowing the argument types of print_student or the number of members in a student tuple, we can directly forward the tuple's content to the function using std::apply. This function accepts a function pointer or a function object and a tuple and then unpacks the tuple in order to call the function with the tuple members as parameters:
apply(print_student, john);
cout << "-----n";
- This also works nicely in a loop, of course:
for (const auto &args : arguments_for_later) {
apply(print_student, args);
}
cout << "-----n";
}
- Compiling and running the program shows that both ways work, as we assumed:
$ ./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
-----