是否存在无需使用宏即可实现token pasting(令牌粘贴)的技术方案?
C++ 无需宏实现重复代码模式的替代方案
你当前遇到的是典型的「变量名+枚举名同步匹配」的重复代码场景,原来的实现依赖C宏的##token拼接能力,现在C++标准已经有无需宏的替代实现方案:
你需要复用的核心逻辑为:
// Token替换为实际变量名 if (Token != PreviousToken) { SomeFunc(SomeEnum::Token,Token); PreviousToken = Token; }
方案1:C++20 模板+编译期字符串匹配(完全无宏)
C++20开始支持把字符串字面量作为模板参数,配合编译期常量判断可以实现和宏完全一致的编译期展开效果,同时自带类型检查,不会出现宏的符号优先级、作用域污染等问题:
#include <string_view> // 通用更新模板 template<std::string_view VarName, typename T> void UpdateIfChanged(T& current, T& prev) { if (current != prev) { // 编译期匹配对应枚举值,无运行时开销 if constexpr (VarName == "Token1") SomeFunc(SomeEnum::Token1, current); else if constexpr (VarName == "Token2") SomeFunc(SomeEnum::Token2, current); // 剩余20+变量依次添加对应匹配分支即可 prev = current; } }
调用方式:
UpdateIfChanged<"Token1">(Token1, PreviousToken1); UpdateIfChanged<"Token2">(Token2, PreviousToken2);
方案2:C++26 静态反射(最优解,无需手动写匹配分支)
C++26已经正式纳入静态反射特性,后续可以直接通过编译期反射自动获取变量名、匹配对应枚举值,连上面的编译期分支都不需要手动编写:
#include <reflect> // C++26标准反射库 template<typename T> void UpdateIfChanged(T& current, T& prev) { if (current != prev) { // 编译期自动获取变量名、匹配对应枚举值 constexpr auto var_name = std::reflect::name_of_v<current>; constexpr auto enum_val = std::reflect::enum_from_name_v<SomeEnum, var_name>; SomeFunc(enum_val, current); prev = current; } }
调用方式更简洁:
UpdateIfChanged(Token1, PreviousToken1); UpdateIfChanged(Token2, PreviousToken2);
低版本编译环境过渡方案
如果当前编译环境不支持C++20,依然优先推荐用宏实现,对比手动写20+份重复代码,宏的维护成本更低,只要做好参数防护即可避免大部分问题:
// 加do while(0)、参数加括号避免宏展开错误 #define UPDATE_IF_CHANGED(Token) \ do { \ if ((Token) != Previous##Token) { \ SomeFunc(SomeEnum::##Token, (Token)); \ Previous##Token = (Token); \ } \ } while(0)
调用方式:UPDATE_IF_CHANGED(Token1);
内容的提问来源于stack exchange,提问作者Eyal K.
相关产品推荐
相关产品推荐

