Colderleo's blog Colderleo's blog
首页
Linux
C++
Python
前端
工具软件
mysql
索引
关于
GitHub (opens new window)

Colder Leo

热爱代码的打工人
首页
Linux
C++
Python
前端
工具软件
mysql
索引
关于
GitHub (opens new window)
  • bug定位的一些情形
  • c++性能调优,可能的情况
  • total-编程知识点集锦
  • hpc_common.hpp
  • memory order 内存模型
  • 类型推导之auto-template-decltype
  • 完美转发forward源码分析
  • 左值和右值,右值引用、重载 std-move,引用折叠
  • cmake用法
  • alignas、alignof、sizeof实现内存对齐分配
  • 通过宏定义控制debug打印
  • 程序耗时性能测试
  • 线程池开源项目阅读
  • C++类中包含没有默认构造函数的成员
  • C++可变参数模板
  • C++属性继承 public protected private
  • C++智能指针
  • C++导出so的方法,以及extern C 注意事项
  • 四种spin lock
  • condition_variable和unique_lock
  • dpdk、kernel bypass
  • 智能网卡solarflare、Mellanox、X10等
  • 汇编寄存器和常见指令
  • c++ 类的静态成员变量未定义
  • C++获取类成员函数地址
  • preload示例
  • C++异常安全和RAII
  • C++11单例模式
  • C++歪门邪道
  • boost-program-option用法
  • c++17通过模板获取类成员的个数
    • 展开解释
    • 优先匹配
  • 通过模板实现结构体成员拷贝-按成员名匹配
  • STL学习路径
  • boost库安装使用方法
  • C++文件读写
  • linux下socket通信demo,server和client
  • makefile写法
  • RxCpp
  • C++
gaoliu
2023-05-01
目录

c++17通过模板获取类成员的个数

通过下面的模板可以获取一个类中成员变量的个数,(包含数组时会有错误,如int a[3]会计算成3个成员)

#include <iostream>
#include <type_traits>
#include <string>
using namespace std;

struct AnyType {
    template<typename T>
    operator T();
};

// 通用的CountMember
template<typename T, typename=void, typename ...Ts>
struct  CountMember{
    constexpr static size_t value = sizeof ...(Ts) - 1;
};

// 这是偏特化的CountMember,优先匹配它,具体原理参考下面的“优先匹配”章节
template<typename T, typename ...Ts>
struct  CountMember<T, std::void_t<decltype(T{Ts{}...})>, Ts...>
{
    constexpr static size_t value = CountMember<T, void, Ts..., AnyType>::value;
};


int main() {
    struct Mem3{int a; char b; string c;};
    std::cout<<CountMember<Mem3>::value << endl; //3

    // 其主要原理是通过匹配Mem3的初始化列表的个数来计算成员的个数。
    // 我们可以尝试用初始化列表构造Mem3对象, 初始化列表最大时,即得到CountMember::value
    {
        Mem3 t{};
        printf("t.a=%d\n", t.a);
    }
    {
        Mem3 t{1, 'c', "abd"}; //初始化列表最多3个member
        printf("t.a=%d\n", t.a);
    }

    // 当成员中含有数组时,例如下面的Mem3Array,初始化列表member个数最多为5
    struct Mem3Array{int a; char b; string c[3];};
    std::cout<<CountMember<Mem3Array>::value << endl; //5
    {
        Mem3Array t{1, 'b'};
        printf("t.a=%d\n", t.a);
    }
    {
        Mem3Array t{1, 'b', "abc", "def"};
        printf("t.a=%d\n", t.a);
    }
    {
        Mem3Array t{1, 'b', "abc", "def", "ghi"}; //初始化列表member个数最多为5
        printf("t.a=%d\n", t.a);
    }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55

# 展开解释

上面的可变参数模板类CountMember相当于创建了下面的多个CM类, 以含有两个成员的struct Mem2为例展开解释:

#include <iostream>
#include <type_traits>
#include <string>
using namespace std;

struct AnyType {
    template<typename T>
    operator T();
};

// 记该类为struct_final
template<typename T, typename=void, typename ...Ts>
struct  CM{
    constexpr static size_t value = sizeof ...(Ts) - 1;
};


// 记该类为struct3
template<typename T>
struct  CM<T, std::void_t<decltype(T{ AnyType{},AnyType{},AnyType{} })>, AnyType, AnyType, AnyType> //简化为<T, void, AnyType, AnyType, AnyType>
{   //因为Mem2不可由含3个member的初始化列表创建,所以里面的decltype匹配不成功,偏特化匹配失败,该类不会被创建,
    constexpr static size_t value = CM<T, void, AnyType, AnyType, AnyType, AnyType>::value;
};

// 记该类为struct2
template<typename T>
struct  CM<T, std::void_t<decltype(T{ AnyType{},AnyType{} })>, AnyType, AnyType> //简化为<T, void, AnyType, AnyType>, 
{  //因为Mem2可由含2个member的初始化列表创建,所以里面的decltype匹配成功

    // 然后根据可变参数模板尝试匹配上面的struct3,匹配不成功,因而匹配struct_final
    // 得到 value = 3-1 = 2
    constexpr static size_t value = CM<T, void, AnyType, AnyType, AnyType>::value; // 匹配struct_final
};

// 记该类为struct1
template<typename T>
struct  CM<T, std::void_t<decltype(T{ AnyType{} })>, AnyType> //简化为<T, void, AnyType>, 
{  //因为Mem2可由含1个member的初始化列表创建,所以里面的decltype匹配成功

    constexpr static size_t value = CM<T, void, AnyType, AnyType>::value; //然后根据可变参数模板创建了上面的struct2
};

// 记该类为struct0
template<typename T>
struct  CM<T, std::void_t<>> //Mem2 首先根据可变参数模板匹配该类,<T,void>, 可变参数数量为0
{
    constexpr static size_t value = CM<T, void, AnyType>::value; //然后根据可变参数模板创建了上面的struct1
};


int main() {
    struct Mem2{int a; char b;};
    std::cout<<"CM<Mem2>="<<CM<Mem2>::value << endl; //匹配struct0, 输出为2
}


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56

# 优先匹配

下面解释偏特化的优先匹配

#include <iostream>
#include <type_traits>
#include <string>
using namespace std;

// 通用的TestSpec
template<typename T, typename=void>
struct TestSpec {
    constexpr static int value = 1;
};

//这是偏特化的TestSpec, 优先匹配它。即便它和通用的TestSpec都接收<T>类型的模板参数
template<typename T>
struct TestSpec<T, void> { 
    constexpr static int value = 2;
};


int main() {
    cout<<TestSpec<char>::value<<endl; //输出2
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
编辑 (opens new window)
上次更新: 2023/05/07, 17:27:54
boost-program-option用法
通过模板实现结构体成员拷贝-按成员名匹配

← boost-program-option用法 通过模板实现结构体成员拷贝-按成员名匹配→

最近更新
01
通过模板实现结构体成员拷贝-按成员名匹配
05-07
02
avx-sse切换惩罚
04-30
03
动态库和静态库的依赖问题
04-30
更多文章>
Theme by Vdoing | Copyright © 2019-2023 Colder Leo | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式
×