C++11 —— 获取 tuple 参数列表中指定数据类型的索引位置

1. 问题背景

??在 C++11 的标准中,我们可以通过 std::get< Index >(tuple) (以常量整数值为索引号)操作 tuple 中的参数,而到了 C++14 之后的标准,新增了 std::get< Type >(tuple) (以数据类型为索引)的方式操作 tuple 中的参数。那么,若只是在 C++11 标准中,是否有办法使用 以数据类型为索引 的方式操作 tuple 中的参数呢?

2. 解决办法

??解决上面所提到的问题,其本质上,就是要解决 如何获取 tuple 参数列表中指定数据类型的索引位置 的问题。凭借这几天我积累到经验(可参看我前几篇关于 tuple 的文章),设计了以下代码中的几个模板类,有效的解决了该问题,请先详细参看如下代码:

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

/**
 * @struct X_type_index
 * @brief  类型索引模板:从变参列表中查找指定类型的索引位置(以 < _Fy, _Indx > 结对进行判断)。
 *
 * @param[in ] _Fy    : 待查找类型。
 * @param[in ] _Indx  : 待查找类型在变参列表中的第几个(以 0 为起始索引)。
 * @param[in ] _Ty... : 变参列表。
 */
template< typename _Fy, size_t _Indx, typename... _Ty >
struct X_type_index;

/**
 * @struct X_type_index_iter
 * @brief  协助 X_type_index 进行 变参列表 递归遍历操作。
 *
 * @param[in ] _Vy    : 模板特化的参数;
 *                      为 true  时,转向 X_type_index_jter 继续进行递归遍历;
 *                      为 false 时,转回 X_type_index 继续进行递归遍历。
 * @param[in ] _Fy    : 待查找类型。
 * @param[in ] _Indx  : 待查找类型在变参列表中的第几个(以 0 为起始索引)。
 * @param[in ] _Ty... : 变参列表。
 */
template< bool _Vy, typename _Fy, size_t _Indx, typename... _Ty >
struct X_type_index_iter;

/**
 * @struct X_type_index_jter
 * @brief  协助 X_type_index_iter 进行 变参列表 递归遍历操作。
 *
 * @param[in ] _Indx  : 待查找类型在变参列表中的第几个(以 0 为起始索引);
 *                      为 0 时,终止递归下降,否则转回 X_type_index 继续进行递归遍历。
 * @param[in ] _Fy    : 待查找类型。
 * @param[in ] _Ty... : 变参列表。
 */
template< size_t _Indx, typename _Fy, typename... _Ty >
struct X_type_index_jter;

/**
 * @brief 终止 X_type_index_jter 递归下降。
 */
template< typename _Fy, typename... _Ty >
struct X_type_index_jter< 0, _Fy, _Ty... >
{
    enum { value = 0 };
};

/**
 * @brief 转回 X_type_index 继续进行递归下降遍历。
 */
template< size_t _Indx, typename _Fy, typename... _Ty >
struct X_type_index_jter
{
    enum { value = 1 + X_type_index< _Fy, _Indx - 1, _Ty... >::value };
};

/**
 * @brief 转向 X_type_index_jter 继续进行递归遍历。
 */
template< typename _Fy, size_t _Indx, typename... _Ty >
struct X_type_index_iter< true, _Fy, _Indx, _Ty... >
{
    enum { value = 0 + X_type_index_jter< _Indx, _Fy, _Ty...>::value };
};

/**
 * @brief 转回 X_type_index 继续进行递归遍历。
 */
template< typename _Fy, size_t _Indx, typename... _Ty >
struct X_type_index_iter< false, _Fy, _Indx, _Ty... >
{
    enum { value = 1 + X_type_index< _Fy, _Indx, _Ty... >::value };
};

/**
 * @brief X_type_index 递归遍历入口。
 */
template< typename _Fy, size_t _Indx, typename _Hy, typename... _Ty >
struct X_type_index< _Fy, _Indx, _Hy, _Ty... >
{
    enum { value = X_type_index_iter< std::is_same< _Fy, _Hy >::value, _Fy, _Indx, _Ty... >::value };
};

/**
 * @brief X_type_index 递归遍历终结位置。
 */
template< typename _Fy, size_t _Indx >
struct X_type_index< _Fy, _Indx >
{
    enum { value = 0x1FFFFFFF };
};

/**
 * @brief 从 tuple 的变参列表中查找指定类型的索引位置(以 < _Fy, _Indx > 结对进行操作)。
 *
 * @param [in ] _Fy   : 待查找类型。
 * @param [in ] _Indx : 待查找类型在变参列表中的第几个(以 0 为起始索引)。
 * @param [in ] _Ty   : tuple 的参数列表。
 *
 * @return size_t
 *         - 返回索引位置;
 *         - 若返回值大于等于 X_type_index< _Fy, _Indx >::value[0x1FFFFFFF] 时,表示未找到查找的类型。
 */
template< typename _Fy, size_t _Indx, typename... _Ty >
constexpr size_t X_tuple_type_index(const std::tuple< _Ty... > &)
{
    return X_type_index< _Fy, _Indx, _Ty... >::value;
}

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

??以上代码中,使用 std::is_same< _Fy, _Hy >::value 判断数据类型是否一致,然后特化 X_type_index_iter<> 和 X_type_index_jter<> 这两个模板类进行递归推导操作,过程中,通过逐步累积索引值到 value 中,最后得到我们需要类型索引值。这过程,如下面的流程图所示:

3. 使用示例

??下面给出完成的测试程序代码,亦可作为使用示例的参看代码:

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

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

/**
 * @struct X_type_index
 * @brief  类型索引模板:从变参列表中查找指定类型的索引位置(以 < _Fy, _Indx > 结对进行判断)。
 *
 * @param[in ] _Fy    : 待查找类型。
 * @param[in ] _Indx  : 待查找类型在变参列表中的第几个(以 0 为起始索引)。
 * @param[in ] _Ty... : 变参列表。
 */
template< typename _Fy, size_t _Indx, typename... _Ty >
struct X_type_index;

/**
 * @struct X_type_index_iter
 * @brief  协助 X_type_index 进行 变参列表 递归遍历操作。
 *
 * @param[in ] _Vy    : 模板特化的参数;
 *                      为 true  时,转向 X_type_index_jter 继续进行递归遍历;
 *                      为 false 时,转回 X_type_index 继续进行递归遍历。
 * @param[in ] _Fy    : 待查找类型。
 * @param[in ] _Indx  : 待查找类型在变参列表中的第几个(以 0 为起始索引)。
 * @param[in ] _Ty... : 变参列表。
 */
template< bool _Vy, typename _Fy, size_t _Indx, typename... _Ty >
struct X_type_index_iter;

/**
 * @struct X_type_index_jter
 * @brief  协助 X_type_index_iter 进行 变参列表 递归遍历操作。
 *
 * @param[in ] _Indx  : 待查找类型在变参列表中的第几个(以 0 为起始索引);
 *                      为 0 时,终止递归下降,否则转回 X_type_index 继续进行递归遍历。
 * @param[in ] _Fy    : 待查找类型。
 * @param[in ] _Ty... : 变参列表。
 */
template< size_t _Indx, typename _Fy, typename... _Ty >
struct X_type_index_jter;

/**
 * @brief 终止 X_type_index_jter 递归下降。
 */
template< typename _Fy, typename... _Ty >
struct X_type_index_jter< 0, _Fy, _Ty... >
{
    enum { value = 0 };
};

/**
 * @brief 转回 X_type_index 继续进行递归下降遍历。
 */
template< size_t _Indx, typename _Fy, typename... _Ty >
struct X_type_index_jter
{
    enum { value = 1 + X_type_index< _Fy, _Indx - 1, _Ty... >::value };
};

/**
 * @brief 转向 X_type_index_jter 继续进行递归遍历。
 */
template< typename _Fy, size_t _Indx, typename... _Ty >
struct X_type_index_iter< true, _Fy, _Indx, _Ty... >
{
    enum { value = 0 + X_type_index_jter< _Indx, _Fy, _Ty...>::value };
};

/**
 * @brief 转回 X_type_index 继续进行递归遍历。
 */
template< typename _Fy, size_t _Indx, typename... _Ty >
struct X_type_index_iter< false, _Fy, _Indx, _Ty... >
{
    enum { value = 1 + X_type_index< _Fy, _Indx, _Ty... >::value };
};

/**
 * @brief X_type_index 递归遍历入口。
 */
template< typename _Fy, size_t _Indx, typename _Hy, typename... _Ty >
struct X_type_index< _Fy, _Indx, _Hy, _Ty... >
{
    enum { value = X_type_index_iter< std::is_same< _Fy, _Hy >::value, _Fy, _Indx, _Ty... >::value };
};

/**
 * @brief X_type_index 递归遍历终结位置。
 */
template< typename _Fy, size_t _Indx >
struct X_type_index< _Fy, _Indx >
{
    enum { value = 0x1FFFFFFF };
};

/**
 * @brief 从 tuple 的变参列表中查找指定类型的索引位置(以 < _Fy, _Indx > 结对进行操作)。
 *
 * @param [in ] _Fy   : 待查找类型。
 * @param [in ] _Indx : 待查找类型在变参列表中的第几个(以 0 为起始索引)。
 * @param [in ] _Ty   : tuple 的参数列表。
 *
 * @return size_t
 *         - 返回索引位置;
 *         - 若返回值大于等于 X_type_index< _Fy, _Indx >::value[0x1FFFFFFF] 时,表示未找到查找的类型。
 */
template< typename _Fy, size_t _Indx, typename... _Ty >
constexpr size_t X_tuple_type_index(const std::tuple< _Ty... > &)
{
    return X_type_index< _Fy, _Indx, _Ty... >::value;
}

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

int main(int argc, char * argv[])
{
    using _Tuple = std::tuple< int, int, int, char, float, double >;

    //======================================
    // 获取索引号

    std::cout << "< int   , 0 > : " << X_type_index< int , 0 >::value << std::endl;
    std::cout << "< int   , 0 > : " << X_type_index< int , 0, int >::value << std::endl;
    std::cout << "< char  , 0 > : " << X_type_index< char, 0, int, int >::value << std::endl;
    std::cout << "< int   , 1 > : " << X_type_index< int , 1, int, int, char >::value << std::endl;
    std::cout << "< char  , 0 > : " << X_type_index< char, 0, int, int, char, char >::value << std::endl;
    std::cout << "< char  , 1 > : " << X_type_index< char, 1, int, int, char, char, char >::value << std::endl;

    std::cout << "tuple type = std::tuple< int, int, int, char, float, double >" << std::endl;
    std::cout << "< int   , 1 > : " << X_tuple_type_index< int   , 1 >(_Tuple{}) << std::endl;
    std::cout << "< int & , 1 > : " << X_tuple_type_index< int & , 1 >(_Tuple{}) << std::endl;
    std::cout << "< char  , 1 > : " << X_tuple_type_index< char  , 1 >(_Tuple{}) << std::endl;
    std::cout << "< double, 1 > : " << X_tuple_type_index< double, 1 >(_Tuple{}) << std::endl;
    std::cout << "< float , 1 > : " << X_tuple_type_index< float , 1 >(_Tuple{}) << std::endl;
    std::cout << "< void *, 1 > : " << X_tuple_type_index< void *, 1 >(_Tuple{}) << std::endl;

    //======================================
    // 按 数据类型方式索引 tuple 的参数

    _Tuple xtuple{ 100, 200, 300, ‘A‘, 1.234F, 1.234 };

    std::cout << " xtpule< 0 > = " << std::get< 0 >(xtuple) << std::endl;
    std::cout << " xtpule< 1 > = " << std::get< 1 >(xtuple) << std::endl;
    std::cout << " xtpule< 2 > = " << std::get< 2 >(xtuple) << std::endl;
    std::cout << " xtpule< 3 > = " << std::get< 3 >(xtuple) << std::endl;
    std::cout << " xtpule< 4 > = " << std::get< 4 >(xtuple) << std::endl;
    std::cout << " xtpule< 5 > = " << std::get< 5 >(xtuple) << std::endl;

    std::get< X_tuple_type_index< int   , 0 >(xtuple) >(xtuple) = 101;
    std::get< X_tuple_type_index< int   , 1 >(xtuple) >(xtuple) = 201;
    std::get< X_tuple_type_index< int   , 2 >(xtuple) >(xtuple) = 301;
    std::get< X_tuple_type_index< char  , 0 >(xtuple) >(xtuple) = ‘B‘;
    std::get< X_tuple_type_index< float , 0 >(xtuple) >(xtuple) = 1.245F;
    std::get< X_tuple_type_index< double, 0 >(xtuple) >(xtuple) = 1.236;

    std::cout << " xtpule< int   , 0 >[0] = " << std::get< 0 >(xtuple) << std::endl;
    std::cout << " xtpule< int   , 1 >[1] = " << std::get< 1 >(xtuple) << std::endl;
    std::cout << " xtpule< int   , 2 >[2] = " << std::get< 2 >(xtuple) << std::endl;
    std::cout << " xtpule< char  , 0 >[3] = " << std::get< 3 >(xtuple) << std::endl;
    std::cout << " xtpule< float , 0 >[4] = " << std::get< 4 >(xtuple) << std::endl;
    std::cout << " xtpule< double, 0 >[5] = " << std::get< 5 >(xtuple) << std::endl;

    //======================================

    return 0;
}

原文地址:https://www.cnblogs.com/VxGaaagaa/p/10159723.html

时间: 2024-08-28 23:27:48

C++11 —— 获取 tuple 参数列表中指定数据类型的索引位置的相关文章

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

问题背景 ??在实现可变参数列表中的类型统计功能前,我们先看看下面代码中的需求场景: /** * @struct x_selector_t< size_t > * @brief 协助 make_task() 接口的特化选择功能的辅助类. */ template< size_t > struct x_selector_t { }; /** * @brief xtuple 参数列表中未包含指定数据类型的时候,创建 x_task_A_t 对象. */ template< typen

查找列表中指定的所有元素的位置

问题:查找列表中指定的值的所有元素 使用list的index方法 1 def find_index(src, key): 2 start_pos = 0 3 for i in range(src.count(key)): 4 if start_pos == 0: 5 start_pos = src.index(key) 6 else: 7 start_pos = src.index(key, start_pos+1) 8 print(start_pos) 9 10 if __name__ ==

用python从字符列表中返回字符串字符的位置

需要从字符列表中找出每个字符在字符串中的位置,然后将整个字符位置返回到单个字符串中,每个字符位置之间的空格除外最后一个.您需要忽略所有不在字符列表中的由az中的字符组成的字符. 策略: 首先,我们需要在列表中声明az字符的列表. alphabetlist = ["a", 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w',

每日学习心得:SharePoint 为列表中的文件夹添加子项(文件夹)、新增指定内容类型的子项、查询列表中指定的文件夹下的内容

前言: 这里主要是针对列表中的文件下新增子项的操作,同时在新建子项时,可以为子项指定特定的内容类型,在某些时候需要查询指定的文件夹下的内容,针对这些场景都一一给力示例和说明,都是一些很小的知识点,希望能够对大家有所帮助. 1.   在列表中为列表项添加子项 为列表添加子项大家都很熟悉,但是如何为列表项添加子项呢?例如列表项是一个文件夹,如何为该文件夹添加子项呢?这里就用到了List.AddItem()方法,具体示例如下: 首先我们要获取列表中的子项: SPListItem root_item=l

获取0至100中指定的数

获取0至100中的0至29,42至100, 刚开始我想的太多,要小于29,大于42,这么多条件什么的.... 不多说了,我自己脑子没转过来 var i,j: integer; begin j := 0; for i := 0 to 99 - 13 do begin memo1.Lines.add(j.ToString()); if i = 29 then j := j + 13 else Inc(j); end; end;

C++11 —— 解包 tuple 参数列表

??tuple 的主要用途,就是把各种类型的参数组合成一个新的数据关联体(结构体),相当于早期的 std::pair 的泛化版本. ??组合存储是方便了,但是,对于某些特定的应用场景,解包就成了个比较麻烦的事情.为此,我查看 gcc 8.2.0 版的 STL 源码,从 functional 文件中 提取出 tuple 索引号生成的代码,并略作更名(避免冲突),得到如下 nstuple 命名空间内的代码,这其中可变参数模板类的递归构建,用得甚是精妙,值得学习. namespace nstuple

获取元素样式对象 页面滚出 页面可是大小 添加监听事件 获取事件参数浏览器中位置 的兼容

/** * 获取浏览滚动出去的距离 * @returns {{scrollY: (Number|number), scrollX: (Number|number)}} */function scroll(){ return{ scrollY:window.scrollY||document.body.scrollTop||document.documentElement.scrollTop||0, scrollX:window.scrollX||document.body.scrollLeft|

将Lambda表达式作为参数传递并解析-在构造函数参数列表中使用Lambda表达式

public class DemoClass { /// <summary> /// 通过Lambda表达式,在构造函数中赋初始值 /// </summary> /// <param name="propertyFunc"></param> /// <param name="propertyValue"></param> public DemoClass (Expression<Func&

python之enumerate函数:获取列表中每个元素的索引和值

源码举例: 1 def enumerate_fn(): 2 ''' 3 enumerate函数:获取每个元素的索引和值 4 :return:打印每个元素的索引和值 5 ''' 6 list = ['Mike', 'male', '24'] 7 for index, value in enumerate(list): 8 print("索引:" + str(index), ", 值:" + value) 9 10 11 enumerate_fn() 运行结果: 索引: