元组和ostream:代码中断时

时间:2018-04-08 23:07:12

标签: c++11 tuples iostream c++17 variadic

使用元组并尝试使用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 个答案:

没有答案