網站首頁 編程語言 正文
一、問題
假設現在有一些屬性以及這些屬性對應的數值類型,比如:
"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)獲取屬性編譯期遞歸實現循環獲取變量類型?
原文鏈接:https://blog.csdn.net/ithiker/article/details/126762469
相關推薦
- 2022-06-06 Docker容器化應用與結構_docker
- 2022-05-25 springboot踩坑日記Feign傳遞MultipartFile詳解
- 2022-05-13 C++ 使用Poco庫實現XML的讀取和寫入
- 2022-10-04 Linux行處理工具之grep?正則表達式詳解_正則表達式
- 2022-06-30 Oracle對PL/SQL中的異常處理_oracle
- 2023-05-21 一文詳解無痕埋點在Android中的實現_Android
- 2022-10-01 Docker部署單頁應用的詳細操作_docker
- 2022-03-17 .NET?6開發TodoList應用引入第三方日志庫_實用技巧
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支