C++11::遍历tuple中的元素

6 篇文章 0 订阅

结尾有彩蛋:-D。


阅读本文之前你需要懂至少一下知识:

  • tuple

    tuple,元组类型。头文件<tuple>,tuple是一个固定大小的不同类型(异质,heterogeneous)值的集合(这一点是tuple与其他常规STL容器的最大不同,即它可以同时存放不同类型的数据),是泛化的std::pair(也即std::pair是tuple的一个特例,长度受限为2)。这里插一句嘴,tuple元组类型是python原生的基本数据类型(C++新标准也引入了lambda函数对象,似乎语言之间有一种互相学习走向趋同的趋势),关于python中的元组类型,可参阅我的Python 基础——list的成员方法

  • decltype

    C++11引入的新的关键字,用以根据变量推导变量的数据类型

  • 非类型模板参数

    关于非类型模板参数详细的内容请参见之前的模板系列,<C++基础——非类型模板参数>

在设计tuple的遍历程序之前,我们不妨先进行std::pair的打印工作:

// #include <utility>
cout << make_pair("InsideZhang", 23) << end;
            // ("InsideZhang", 23)

为了实现上述的功能,我们需要重载<<运算符。

template<typename T1, typename T2>
std::ostream& pair_print(std::ostream& os, const pair<T1, T2>& p)
{
    return os << "(" << p.first << ", " << p.second << ")";
}

当我们试图仿照上例的形式实现对tuple的遍历输出时:

template<typename... Args>
std::ostream& operator<<(std::ostream& os, const std::tuple<Args...>& t)
{
    os << "(" << std::get<0>(t);
    for (size_t i = 1; i < sizeof...(Args) << ++i)
        os << ", " << std::get<i>(t);
    return os << "]";
}

int main(int, char**)
{
    cout << make_tuple("InsideZhang", 23, "HeNan") << endl;
            // 编译出错,局部变量i不可作为非类型模板参数
    return 0;
}

这时我们便需要单独把每一位的索引拿出来作为非类型模板参数进行递归调用:

template<typename Tuple>
void tuple_print(const Tuple& t, size_t N, std::ostream& os)
{
    if (N != 1)
        tuple_print(t, N-1, os);
    os << std::get<N-1>(t);
}

以上的代码, 也即通过参数传递的方式进行的非类型模板参数的赋值,仍然编译不通过。非类型模板参数必须在编译时即为常量表达式。

template<typename Tuple, size_t N>
void tuple_print(const Tuple& t, std::ostream& os)
{
    if (N != 1)
        tuple_print<Tuple, N-1>(t, os);
    os << std::get<N-1>(t);
}

这样做似乎也编译不通过,具体为什么,一时也想不出来,大家有什么思路和想法不妨提供一下。

以下是一个通行的解决方案:

template<typename Tuple, size_t N>
struct tuple_print
{
    static void print(const Tuple& t, std::ostream& os)
    {
        tuple_print<Tuple, N-1>::print(t, os);
        os << ", " << std::get<N-1>(t); 
    }
};
// 类模板的特化版本
template<typename Tuple>
struct tuple_print<Tuple, 1>
{
    static void print(const Tuple& t, std::ostream& os)
    {
        os << "(" << std::get<0>(t); 
    }
};

// operator<<
template<typename... Args>
std::ostream& operaotr<<(std::ostream& os, const std::tuple<Args...>& t)
{
    tuple_print<decltype(t), sizeof...(Args)>::print(t, os);
    return os << ")";
}

客户端代码:

auto t1 = std::make_tuple("InsideZhang", 23, "HeNan");
auto t2 = std::make_tuple("InsideLi", 23, "AnHui");
// tuple_cat()   元组拼接
// 调用operator<< 运算符重载
std::cout << std::tuple_cat(t1, t2) << std::endl;
//  (InsideZhang, 23, HeNan, InsideLi, 23, AnHui)

因为tuple类没有重载operator[]运算符,很难像其他容器和数据额结构一样进行简洁的索引动作,只能通过一个全局的std::get<size_t>(t)进行操作。

tuple class最早公开于Boost程序库。在那儿,tuple可以将元素写至output stream,不知道为什么C++标准库不支持这一性质,而是需要我们花费一些精力手动完成这一工作。

#include <iostream>
#include <boost\tuple\tuple_io.hpp>

int main(int, char**)
{
    std::cout << boost::make_tuple("InsideZhang", 23, "HeNan") << std::endl;
    return 0;
}

References

[1]<Pretty-print std::tuple>

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

五道口纳什

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值