Кортежи и ostreams: когда код ломается
При работе с кортежами и попытке вывести их значения на консоль с помощью ostream вы не можете напрямую использовать цикл для этого, поскольку вы можете получить доступ только к элементам кортежа из std::get, который ожидает постоянную времени компиляции в качестве аргумента шаблона., Поэтому мы должны использовать магию шаблонов и рекурсию, чтобы сделать это для нас; справедливо. У меня есть рабочий код, который вы можете увидеть ниже, который будет печатать кортеж через ostream, если все его типы являются базовыми:
#include <utility>
#include <iostream>
#include <tuple>
template<std::size_t> struct int_ {};
template<class Tuple, size_t Pos>
std::ostream& print_tuple( std::ostream& out, const Tuple& t, int_<Pos> ) {
out << std::get<std::tuple_size<Tuple>::value - Pos>( t ) << ' ';
return print_tuple( out, t, int_<Pos - 1>() );
}
template<class Tuple>
std::ostream& print_tuple( std::ostream& out, const Tuple& t, int_<1> ) {
return out << std::get<std::tuple_size<Tuple>::value - 1>( t );
}
template<class... Args>
std::ostream& operator<<( std::ostream& out, const std::tuple<Args...>& t ) {
return print_tuple( out, t, int_<sizeof...(Args)>() );
}
int main() {
std::tuple<int, double, std::string> sample = std::make_tuple( 3, 1.723, "Hi!" );
std::cout << sample << '\n';
std::cout << "\nPress any key and enter to quit.\n";
std::cin.get();
return 0;
}
Output
3 1.723 Hi!
Press any key to quit.
Это кажется достаточно простым; но подождите: что, если один из элементов кортежей НЕ является базовым типом? Что если один из элементов окажется контейнером, таким как вектор, список, набор или карта? Этот код не работает и не работает. Давайте использовать тот же код выше с другим тестовым образцом кортежа:
int main() {
// This next line is perfectly fine and compiles without problems
std::tuple<int, double, std::vector<int>> sample2 =
( 1, 2.0, std::vector<int>{ 3,4,5 } );
// Let's use our overloaded operator from before:
std::cout << sample2 << '\n';
// Oh no; the code doesn't even compile any more!
std::cout << "\nPress any key and enter to quit.\n";
std::cin.get();
return 0;
}
Как видно из приведенного выше примера, перегруженный оператор для кортежа подходит для всех <Args...>
это основные типы; но код ломается, как только один из них является контейнером или другим пользовательским типом.
Как можно решить это? Я не обязательно ищу один случай, который подходит всем. Конкретный случай, который мне нужен в моем кортеже, std::vector<int>
как показано выше. Если бы я мог показать мне, как получить перегруженный operator<<()
для работы с кортежем std::vector<int>
Я уверен, что могу обобщить это, чтобы работать для любого std::vector<T>
пока <T>
это основной тип.