C++编译期循环获取变量类型详情

 更新时间:2022年09月09日 10:37:58   作者:ithiker  
这篇文章主要介绍了C++编译期循环获取变量类型详情,文章围绕主题展开详细的内容介绍,具有一定的参考价值,感兴趣的小伙伴可以参考一下

一、问题

假设现在有一些属性以及这些属性对应的数值类型,比如:

"gender" --> char
"age" --> int
"height" --> float
"IQ" ---> int
"name" --> std::string
"weight" --> double

在C++中,如何在编译期依次循环获取这些属性的数值类型,并根据对应的数值类型做出相应的处理(属性可能会增加)

二、解决方案

1.定义类型

首先把所有可能的类型用std::tuple列出:

using Types = std::tuple<float, int, double, std::string, char>;

template<std::size_t N>
using AttributeType = typename std::tuple_element<N, Types>::type;

这里,通过AttributeType<0>就可以得到float 类型

2.定义属性集

将所有的属性和其类型的对应关系列出,由于需要是编译期获得,必须类似加入constexpr 关键字:

constexpr const char* FLOAT_TYPE = "float";
constexpr const char* INT_TYPE = "int";
constexpr const char* DOUBLE_TYPE = "double";
constexpr const char* STRING_TYPE = "std::string";
constexpr const char* CHAR_TYPE = "float";

constexpr std::array<std::pair<const char*, const char*>, 6> attribute2type = {{
    {"gender", CHAR_TYPE},
    {"age", INT_TYPE},
    {"height", FLOAT_TYPE},
    {"IQ", INT_TYPE},
    {"name", STRING_TYPE},
    {"weight", DOUBLE_TYPE},
}};

3. 获取类型索引

根据2中定义的类型字符串,获取1中需要的类型索引N:

constexpr std::size_t getTypeIndex(const char* name)
{
    return strings_equal(name, "float") ? 0:
        strings_equal(name, "int") ? 1:
        strings_equal(name, "double") ? 2:
        strings_equal(name, "std::string") ? 3:
        strings_equal(name, "char") ? 4:
        5; // compilation error
}

这里,需要一个编译期进行字符串比较的函数:

constexpr bool strings_equal(const char* a, const char* b) {
    return *a == *b && (*a == '\0' || strings_equal(a + 1, b + 1));
}

4. 编译期循环

如何实现编译期的类似for循环呢,显然不能直接用for,模板的特性决定了可以使用编译期递归来进行替代for循环:

template <typename T>
void print(const char* attribute) {
    std::cout << "attribute = " << attribute << ",type=" <<  typeid(T).name() << std::endl;
}
constexpr size_t LAST_INDEX = attribute2type.size() - 1;
template <size_t T=LAST_INDEX>
struct PrintHelper {

    public:
        PrintHelper() {
            doPrint<T>();
        }
    private:
        template <size_t N>
        void doPrint() {
            print<AttributeType<getTypeIndex(std::get<N>(attribute2type).second)>>(std::get<N>(attribute2type).first);
            doPrint<N-1>();

        }

};
template <>
template <>
void PrintHelper<LAST_INDEX>::doPrint<0>() {
    print<AttributeType<getTypeIndex(std::get<0>(attribute2type).second)>>(std::get<0>(attribute2type).first);
}

将上面所有的代码放到一块,就得到了一个可以在编译期循环获取变量类型的程序:

#include <string>
#include <iostream>
#include <typeinfo>
#include <tuple>
#include <array>

using Types = std::tuple<float, int, double, std::string, char>;
template<std::size_t N>
using AttributeType = typename std::tuple_element<N, Types>::type;

constexpr bool strings_equal(const char* a, const char* b) {
    return *a == *b && (*a == '\0' || strings_equal(a + 1, b + 1));
}
constexpr std::size_t getTypeIndex(const char* name)
{
    return strings_equal(name, "float") ? 0:
        strings_equal(name, "int") ? 1:
        strings_equal(name, "double") ? 2:
        strings_equal(name, "std::string") ? 3:
        strings_equal(name, "char") ? 4:
        5; // compilation error
}
constexpr const char* FLOAT_TYPE = "float";
constexpr const char* INT_TYPE = "int";
constexpr const char* DOUBLE_TYPE = "double";
constexpr const char* STRING_TYPE = "std::string";
constexpr const char* CHAR_TYPE = "float";

constexpr std::array<std::pair<const char*, const char*>, 6> attribute2type = {{
    {"gender", CHAR_TYPE},
    {"age", INT_TYPE},
    {"height", FLOAT_TYPE},
    {"IQ", INT_TYPE},
    {"name", STRING_TYPE},
    {"weight", DOUBLE_TYPE},
}};

template <typename T>
void print(const char* attribute) {
    std::cout << "attribute = " << attribute << ",type=" <<  typeid(T).name() << std::endl;
}
constexpr size_t LAST_INDEX = attribute2type.size() - 1;

template <size_t T=LAST_INDEX>
struct PrintHelper {

    public:
        PrintHelper() {
            doPrint<T>();
        }
    private:
        template <size_t N>
        void doPrint() {
            print<AttributeType<getTypeIndex(std::get<N>(attribute2type).second)>>(std::get<N>(attribute2type).first);
            doPrint<N-1>();

        }

};
template <>
template <>
void PrintHelper<LAST_INDEX>::doPrint<0>() {
    print<AttributeType<getTypeIndex(std::get<0>(attribute2type).second)>>(std::get<0>(attribute2type).first);
}
int main() {
    PrintHelper<LAST_INDEX>();

    return 0;
}

上面程序输出:

$ ./attributeWithType 
attribute = weight,type=d
attribute = name,type=NSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE
attribute = IQ,type=i
attribute = height,type=f
attribute = age,type=i
attribute = gender,type=f

总结

本文通过下面几个技术点实现了编译期循环获取变量类型:

  • 通过std::tuple定义变量类型集合,
  • 通过typename std::tuple_element<N, Types>::type获取某个变量类型
  • 通过编译期递归实现编译期字符串比较
  • 通过std::get(attribute2type)获取属性编译期递归实现循环获取变量类型 

到此这篇关于C++编译期循环获取变量类型详情的文章就介绍到这了,更多相关C++循环获取变量类型内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 使用MinGW使Windows通过gcc实现C或C++程序本地编译执行的方法

    使用MinGW使Windows通过gcc实现C或C++程序本地编译执行的方法

    这篇文章主要介绍了使用MinGW使Windows通过gcc实现C或C++程序本地编译执行的方法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-11-11
  • 基于C语言实现三子棋游戏

    基于C语言实现三子棋游戏

    这篇文章主要为大家详细介绍了基于C语言实现三子棋游戏,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-08-08
  • C++ Opencv实现录制九宫格视频

    C++ Opencv实现录制九宫格视频

    这篇文章主要为大家介绍了如何利用C++和OpenCV库实现录制九宫格视频,文中的示例代码讲解详细,对我们学习OpenCV有一定帮助,感兴趣的可以了解一下
    2022-05-05
  • 深入理解C/C++中的写时拷贝

    深入理解C/C++中的写时拷贝

    这篇文章主要给大家介绍了C/C++中写时拷贝的相关资料,所谓写时拷贝也就是拖延版的深拷贝,下面文章中介绍的非常清楚,需要的朋友可以参考学习,下面来一起看看吧。
    2017-03-03
  • 排列和组合算法的实现方法_C语言经典案例

    排列和组合算法的实现方法_C语言经典案例

    下面小编就为大家带来一篇排列和组合算法的实现方法_C语言经典案例。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2016-09-09
  • C++模板template用法小结(推荐)

    C++模板template用法小结(推荐)

    这篇文章主要介绍了C++模板template用法总结 ,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-03-03
  • 详解C++17中的decltype类型推导

    详解C++17中的decltype类型推导

    这篇文章主要介绍了C++17中的decltype类型推导,本文从泛型编程中经常会遇到2个常见问题入手,循序渐进的分析了从C++11开始引入的关键字decltype,需要的朋友可以参考下
    2023-06-06
  • C++ 如何使用栈求解中缀、后缀表达式的值

    C++ 如何使用栈求解中缀、后缀表达式的值

    这篇文章主要介绍了C++ 使用栈求解中缀、后缀表达式的值,本文讲解了中缀、后缀表达式的求值过程以及如何将一个中缀表达式转换成后缀表达式,需要的朋友可以参考下
    2022-10-10
  • C语言数据结构之链队列的基本操作

    C语言数据结构之链队列的基本操作

    这篇文章主要为大家介绍了C语言之链队列的基本操作,具有一定的参考价值,感兴趣的小伙伴们可以参考一下,希望能够给你带来帮助
    2021-12-12
  • C语言编程中分配内存空间的相关函数

    C语言编程中分配内存空间的相关函数

    这篇文章主要介绍了C语言编程中分配内存空间的相关函数,分别是malloc()函数和calloc()函数,需要的朋友可以参考下
    2015-08-08

最新评论