C++17中向宏传递任意带逗号模板类的技巧及默认无依赖实现
C++17中向宏传递任意带逗号模板类及默认无依赖的解决方案
一、解决宏解析含逗号模板类的核心技巧
宏会将逗号视为参数分隔符,导致带逗号的模板类(如std::map<std::string, std::vector<double>>)被错误拆分。解决方法是用括号包裹每个带逗号的类型,再通过辅助宏提取括号内的完整类型:
- 传递参数时的写法:
my_macro( (std::map<std::string, std::vector<double>>), double, (std::deque<std::pair<bool,double>>) ) - 定义辅助宏提取类型:
宏内部处理参数时,用#define UNPAREN(...) __VA_ARGS__ #define GET_TYPE(t) UNPAREN tGET_TYPE(t)即可获取括号内的完整类型。
二、默认无依赖的实现方案
针对无需显式声明无依赖的需求,可通过宏的条件编译+类内类型别名实现,避免重复调用wrapper_no_dependencies:
方案1:包装类模板带默认空tuple参数
将包装类设计为模板,默认依赖类型设为std::tuple<>,无依赖时无需额外声明:
#include <tuple> #include <utility> template<typename T, typename Dependencies = std::tuple<>> class Wrapper { public: using dependencies__ = Dependencies; static void expose() { // 暴露当前类成员的逻辑 // ... // 遍历依赖调用expose std::apply([](auto&&... args) { (decltype(args)::expose(), ...); }, dependencies__{}); } };
配合宏声明具体类的包装:
#define wrapper_declare(CLASS_TYPE, ...) \ template<typename... Args> \ class Wrapper<CLASS_TYPE<Args...>> : public BaseWrapper { \ using dependencies__ = std::tuple<GET_TYPE(__VA_ARGS__)...>; \ // 构造函数、成员声明等逻辑 \ }; // 无依赖调用:wrapper_declare(Hello) // 有依赖调用:wrapper_declare(Hello, (Wrapper<Foo>), (Wrapper<Bar<int>>))
方案2:C++17兼容的宏条件判断
利用宏的可变参数特性,定义自动判断是否为空的宏,为空时默认生成空tuple:
// 辅助宏:处理依赖类型 #define DEPENDENCY_TYPE(...) \ DEPENDENCY_TYPE_IMPL(__VA_ARGS__, std::tuple<GET_TYPE(__VA_ARGS__)...>, std::tuple<>) #define DEPENDENCY_TYPE_IMPL(a, b, c, ...) b // 包装类声明宏 #define wrapper_declare(CLASS_TYPE, ...) \ class Wrapper_##CLASS_TYPE : public BaseWrapper { \ public: \ DEPENDENCY_TYPE(__VA_ARGS__) \ \ static void expose() { \ // 当前类暴露逻辑 \ std::apply([](auto&&... dep_wrappers) { \ (decltype(dep_wrappers)::expose(), ...); \ }, dependencies__{}); \ } \ // 构造函数等其他声明 \ };
当调用wrapper_declare(Hello)时,DEPENDENCY_TYPE会生成std::tuple<>;传递依赖时则生成包含指定类型的tuple。
三、完整代码示例
#include <tuple> #include <iostream> #include <string> #include <vector> // 辅助宏:去掉括号提取类型 #define UNPAREN(...) __VA_ARGS__ #define GET_TYPE(t) UNPAREN t // 依赖类型处理宏 #define DEPENDENCY_TYPE(...) \ DEPENDENCY_TYPE_IMPL(__VA_ARGS__, std::tuple<GET_TYPE(__VA_ARGS__)...>, std::tuple<>) #define DEPENDENCY_TYPE_IMPL(a, b, c, ...) b // 基础包装类 class BaseWrapper { public: virtual ~BaseWrapper() = default; virtual void expose() = 0; }; // 通用包装类模板 template<typename T> class Wrapper : public BaseWrapper { public: using dependencies__ = std::tuple<>; void expose() override { std::cout << "Exposing generic type: " << typeid(T).name() << "\n"; std::apply([](auto&&...) {}, dependencies__{}); } }; // 自定义类声明宏 #define wrapper_declare(CLASS_TYPE, ...) \ template<typename... Args> \ class Wrapper<CLASS_TYPE<Args...>> : public BaseWrapper { \ public: \ DEPENDENCY_TYPE(__VA_ARGS__) \ \ void expose() override { \ std::cout << "Exposing " << typeid(CLASS_TYPE<Args...>).name() << "\n"; \ std::apply([](auto&&... deps) { \ (decltype(deps)::expose(), ...); \ }, dependencies__{}); \ } \ }; // 示例模板类 template<typename T> class Foo {}; template<typename T, typename U> class Bar {}; // 无依赖包装声明 wrapper_declare(Foo) // 带依赖包装声明 wrapper_declare(Bar, (Wrapper<Foo<int>>), (Wrapper<std::vector<std::string>>)) int main() { Wrapper<Bar<double, float>> bar_wrapper; bar_wrapper.expose(); return 0; }
内容的提问来源于stack exchange,提问作者Caduchon
相关产品推荐
相关产品推荐

