Кортежи и 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> это основной тип.

0 ответов

Другие вопросы по тегам