首页 > 编程语言 > 详细

C++11 —— 统计 tuple 中指定数据类型的数量

时间:2020-01-01 23:48:09      阅读:164      评论:0      收藏:0      [点我收藏+]

问题背景

??在实现可变参数列表中的类型统计功能前,我们先看看下面代码中的需求场景:

/**
 * @struct x_selector_t< size_t >
 * @brief  协助 make_task() 接口的特化选择功能的辅助类。
 */
template< size_t >
struct x_selector_t
{

};

/**
 * @brief xtuple 参数列表中未包含指定数据类型的时候,创建 x_task_A_t 对象。
 */
template< typename... _Args >
x_task_t * make_task(const x_selector_t< 0 > &, std::tuple< _Args... > && xtuple)
{
    using _Tuple = typename std::tuple< _Args... >;
    return (new x_task_A_t(std::forward< _Tuple >(xtuple)));
}

/**
 * @brief xtuple 参数列表中包含指定数据类型 1 个的时候,创建 x_task_B_t 对象。
 */
template< typename... _Args >
x_task_t * make_task(const x_selector_t< 1 > &, std::tuple< _Args... > && xtuple)
{
    using _Tuple = typename std::tuple< _Args... >;
    return (new x_task_B_t(std::forward< _Tuple >(xtuple)));
}

/**
 * @brief xtuple 参数列表中包含指定数据类型 2 个的时候,创建 x_task_C_t 对象。
 */
template< typename... _Args >
x_task_t * make_task(const x_selector_t< 2 > &, std::tuple< _Args... > && xtuple)
{
    using _Tuple = typename std::tuple< _Args... >;
    return (new x_task_C_t(std::forward< _Tuple >(xtuple)));
}

??上面的代码中,x_task_A_t, x_task_B_t, x_task_C_t 都是 x_task_t 的派生类,按照上面已经提供的三个 make_task() 接口,我们能不能只提供一个接口(如下面的代码所示),就可自动选择这三个接口之一创建 x_task_t 对象呢?当然可以,只要我们解决 “怎么统计 tuple 中指定数据类型的数量” 这个问题就能办到。

/**
 * @brief 自动统计 _Ty 数据类型在 xtuple 参数列表中的数量,
 *        然后选择对应的 make_task() 接口,创建 x_task_t 对象。
 */
template< typename _Ty, typename... _Args >
x_task_t * create_task(const x_selector_t< 2 > &, std::tuple< _Args... > && xtuple)
{
    using _Tuple = typename std::tuple< _Args... >;

    constexpr size_t const xty_count = ...; // 统计 _Ty 在 _Args... 参数列表中的数量

    // 当前只有三种方式创建对象,增加编译期的断言判断
    static_assert(xty_count < 3, "There are currently only three ways to create x_task_t!");

    // 使用 x_selector_t< xty_count >() 特化对象,进行接口选择
    return make_task(x_selector_t< xty_count >(), std::forward< _Tuple >(xtuple)));
}

解决办法

??为解决可变参数列表种的类型统计问题,我们可以利用 C++11 的可变参数模板类的自动推导的特性,实现这一功能,请看下面代码所给出了解决的方案:


/** X_type_count 的前置声明 */
template< typename _Fy, typename... _Ty >
struct X_type_count;

/**
 * @struct X_type_count< _Fy, _Hy, _Ty... >
 * @brief  递归的数据类型统计类。
 */
template< typename _Fy, typename _Hy, typename... _Ty >
struct X_type_count< _Fy, _Hy, _Ty... >
{
    enum { value = (int)(std::is_same< _Fy, _Hy >::value) + X_type_count< _Fy, _Ty... >::value };
};

/**
 * @struct X_type_count< _Fy >
 * @brief  终止递归的数据类型统计类。
 */
template< typename _Fy >
struct X_type_count< _Fy >
{
    enum { value = 0 };
};

/**
 * @brief 统计 tuple 对象内某个数据类型的数量。
 */
template< typename _Fy, typename... _Ty >
constexpr size_t X_tuple_type_count(const std::tuple< _Ty... > &)
{
    return X_type_count< _Fy, _Ty... >::value;
}

??细看 X_type_count< _Fy, _Hy, _Ty... >::value 值的实现方式,我们用标准库提供的 std::is_same< _Fy, _Hy >::value 进行类型判断,将判断结果的 bool 值强制转换为为整数(0 或 1),然后累加到 value 中;下一步再以递归方式累加 X_type_count< _Fy, _Ty... >::value 的值,最后逐步地统计到整个可变参数列表中指定类型的数量。

??完整的测试代码如下:

#include <type_traits>
#include <tuple>
#include <iostream>

////////////////////////////////////////////////////////////////////////////////

/** X_type_count 的前置声明 */
template< typename _Fy, typename... _Ty >
struct X_type_count;

/**
 * @struct X_type_count< _Fy, _Hy, _Ty... >
 * @brief  递归的数据类型统计类。
 */
template< typename _Fy, typename _Hy, typename... _Ty >
struct X_type_count< _Fy, _Hy, _Ty... >
{
    enum { value = (int)(std::is_same< _Fy, _Hy >::value) + X_type_count< _Fy, _Ty... >::value };
};

/**
 * @struct X_type_count< _Fy >
 * @brief  终止递归的数据类型统计类。
 */
template< typename _Fy >
struct X_type_count< _Fy >
{
    enum { value = 0 };
};

/**
 * @brief 统计 tuple 对象内某个数据类型的数量。
 */
template< typename _Fy, typename... _Ty >
constexpr size_t X_tuple_type_count(const std::tuple< _Ty... > &)
{
    return X_type_count< _Fy, _Ty... >::value;
}

////////////////////////////////////////////////////////////////////////////////

int main(int argc, char * argv[])
{
    std::cout << "X_type_count< int, _Ty... > : "
              << X_type_count< int, int, int, char, char, double >::value << std::endl;

    using _XTuple = std::tuple< int, int, int, char, char, double >;
    std::cout << "tuple type : std::tuple< int, int, int, char, char, double > " << std::endl;
    std::cout << "X_tuple_type_count< int    > : " << X_tuple_type_count< int    >(_XTuple{}) << std::endl;
    std::cout << "X_tuple_type_count< char   > : " << X_tuple_type_count< char   >(_XTuple{}) << std::endl;
    std::cout << "X_tuple_type_count< double > : " << X_tuple_type_count< double >(_XTuple{}) << std::endl;
    std::cout << "X_tuple_type_count< float  > : " << X_tuple_type_count< float  >(_XTuple{}) << std::endl;
    std::cout << "X_tuple_type_count< void * > : " << X_tuple_type_count< void * >(_XTuple{}) << std::endl;

    return 0;
}

??输出结果如下:

X_type_count< int, _Ty... > : 2
tuple type : std::tuple< int, int, int, char, char, double >
X_tuple_type_count< int    > : 3
X_tuple_type_count< char   > : 2
X_tuple_type_count< double > : 1
X_tuple_type_count< float  > : 0
X_tuple_type_count< void * > : 0

C++11 —— 统计 tuple 中指定数据类型的数量

原文:https://www.cnblogs.com/Gaaagaa/p/12130416.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!