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

目录
  • 一、问题
  • 二、解决方案
    • 1.定义类型
    • 2.定义属性集
    • 3. 获取类型索引
    • 4. 编译期循环
  • 总结

一、问题

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

"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++循环获取变量类型内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • 获取C++变量类型的简单方法

    目录 获取C++变量类型 与传统方法的对比 获取C++数据类型取值范围 包含头文件 类型变量定义 取类型值范围 完整代码 获取C++变量类型 直接上代码 #include <type_traits> #include <typeinfo> #include <memory> #include <string> #include <cstdlib> #include <iostream> #ifndef _MSC_VER #includ

  • 详解c++中的类型识别

    1.类型识别的相关概念 (1)类型识别的作用 类型识别是面向对象中引入的一个新概念,主要用来判断赋值兼容性原则中的类型问题,即此时的数据类型到底是基类类型还是派生类类型? 当基类指针指向子类对象 或者基类引用成为子类对象的别名 时,就需要使用类型识别: Base *p = new Derived(); Base &r = *p 对于上面的语句,我们可以这样认识,指针p是Base类型,但是P 又指向了一个新的Derived类型,此时很难判断指针P 的数据类型:同理,引用r 本来作为父类的别名而存在

  • C++变量和基本类型详解

    目录 基本内置类型 1. 不同平台下基本类型的字节数 2. 算数类型的最小尺寸 3. 数据类型选择的经验准则 4. 有符号类型和无符号类型 5.初始化与赋值 6. 声明与定义 7. C++关键字 8.1 初始化 8.2 const引用 8.3 const与指针 小结: 9. constexpr 和常量表达式 10. 处理类型 总结 基本内置类型 算术类型分为两类:整型(包括字符和布尔类型在内)和浮点型 1. 不同平台下基本类型的字节数 类型 16位平台 32位平台 64位平台 char 1 1

  • 从汇编看c++中变量类型的深入分析

    全局变量的生命期和可见性是整个程序的运行期间,下面就来用汇编来看一下实际情况: c++源码: 复制代码 代码如下: int i = 2;//全局变量 int main() {    int j = i;} 下面是汇编代码: 复制代码 代码如下: PUBLIC    ?i@@3HA                        ; i_DATA    SEGMENT?i@@3HA    DD    02H                    ; 全局变量i内存空间_DATA    ENDSPUB

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

    目录 一.问题 二.解决方案 1.定义类型 2.定义属性集 3. 获取类型索引 4. 编译期循环 总结 一.问题 假设现在有一些属性以及这些属性对应的数值类型,比如: "gender" --> char "age" --> int "height" --> float "IQ" ---> int "name" --> std::string "weight"

  • Golang反射获取变量类型和值的方法详解

    目录 1. 什么是反射 2. reflect.Type 2.1 类型Type和种类Kind 2.2 引用指向元素的类型 2.3 结构体成员类型 3. reflect.Value 3.1 结构体的成员的值 3.2 遍历array.slice 3.3 遍历map 4. 反射的三大定律 4.1 从interface到反射对象 4.2 从反射对象到interface 4.3 通过反射修改对象,该对象值必须是可修改的 1. 什么是反射 反射是程序在运行期间获取变量的类型和值.或者执行变量的方法的能力. G

  • golang获取变量或对象类型的几种方式总结

    目录 fmt.Printf("%T")方式 用fmt.Printf("%T")实现返回变量类型的函数 reflect.TypeOf方式 用reflect.TypeOf实现返回变量类型的函数 reflect.ValueOf.Kind()方式 用 reflect.ValueOf.Kind()实现返回变量类型的函数 断言方式 代码示例: 结果演示: 总结 fmt.Printf("%T")方式 示例: var1 := "hello world&

  • PowerShell中使用GetType获取变量数据类型

    本文介绍在PowerShell中如何获取变量的数据类型,使用GetType()函数来完成此任务. 首先看一个例子: 复制代码 代码如下: PS C:\Users\zhanghong> $i=1 PS C:\Users\zhanghong> $i.gettype() IsPublic IsSerial Name                                     BaseType -------- -------- ----                          

  • 详解在JavaScript中如何判断变量类型

    JavaScript是一个动态类型语言,在运行时获取变量类型是常用操作,由于JavaScript设计的问题,看似简单的问题,在JavaScript中可能并不简单,比如在社区中流传的下图,仔细看一下这些坑,即便是JavaScript老司机也经常翻车. 上图中typeof NaN会返回number,这可能和你想的不一样,在JavaScript准确的获取变量类型,并不简单,正因为如此,这个问题经常被用来考察面试者,由于程序=数据+算法,而基本数据是数据的基础,所以面试中考察类型也是合理的. 如果面试中

  • JavaScript用构造函数如何获取变量的类型名

    使用 typeof 获取基本的类型 看到题目的第一眼,有些同学可能会想到 typeof 运算符,在JavaScript语言中,给出了使用 typeof 运算符来获取基本的类型名.(注意不是基本类型) 这是 typeof 的全部用法 01-typeof.htm console.log('typeof of 10 ~~~~' +typeof 10); console.log('typeof of "a" ~~~~' +typeof 'a'); console.log('typeof of

  • 使用typescript推导已有变量的盲盒类型详情

    目录 迁移盲盒 类型推导 基础类型的推导 对象的推导 数组的推导 函数的推导 完善推导 测试 迁移盲盒 当我们从JavaScript一键转换Typescript的时候,any便是最省事的做法,对于维护并不友好(虽然能跑就行),同时每个变量对于我们来说都是盲盒,它到底是什么类型? 类型推导 基础类型的推导 基础数据类型的类型推导还是挺简单的 let a = 1; type A = typeof a; // number; let b = '2' type B = typeof b; // stri

  • Go语言的变量定义详情

    目录 一.变量 声明变量 二.短声明 指针 三.new函数 四.变量的生命期 五.变量的作用域 一.变量 声明变量 go定义变量的方式和c,c++,java语法不一样,如下: var 变量名 类型, 比如 : var a int var在前,变量名在中间,类型在后面 我们以代码举例,如下: var i int = 0 var i = 0 var i int 以上三个表达式均是合法的,第三个表达式会将i初始化为int类型的零值,0:如果i是bool类型,则为false:i是float64类型,则为

  • Android 利用 APT 技术在编译期生成代码

    APT(Annotation Processing Tool 的简称),可以在代码编译期解析注解,并且生成新的 Java 文件,减少手动的代码输入.现在有很多主流库都用上了 APT,比如 Dagger2, ButterKnife, EventBus3 等,我们要紧跟潮流,与时俱进呐! (ง •̀_•́)ง 下面通过一个简单的 View 注入项目 ViewFinder 来介绍 APT 相关内容,简单实现了类似于ButterKnife 中的两种注解 @BindView 和 @OnClick . 项目

随机推荐