C++如何从宏的可变参数中获取对应的类型参数包?
解决方案
问题核心原因
- C++ 标准不存在
decltype...(可变参数)语法,你的原有写法不符合语法规则 - 直接写
decltype(__VA_ARGS__)时,__VA_ARGS__内部的逗号会被识别为逗号运算符,最终仅返回最后一个参数的类型,无法得到完整的类型参数包
最优实现方案
利用函数模板的自动类型推导能力实现需求,不需要参数满足 constexpr 要求,也不需要修改原有 myFunctionHelper 逻辑:
template<std::size_t N, class T, class... Ts> constexpr bool myFunctionHelper(const char (&fmt)[N], std::size_t n); // 仅修改myFunction签名,增加的参数包仅用于推导类型,不会读取参数值 template <std::size_t N, typename... Ts> constexpr bool myFunction(const char (&fmt)[N], Ts&&...) { return myFunctionHelper<N, Ts...>(fmt, 0); } #define FNC(fmt, ...) \ do { \ /* ##__VA_ARGS__用于兼容无可变参数传入的场景 */ \ static_assert(myFunction(fmt, ##__VA_ARGS__), \ "Incorrect arg types"); \ } while (false)
方案说明
- 调用
myFunction时编译器会自动根据传入的参数推导Ts...类型包,完全匹配你需要的所有参数类型 - 因为
myFunction内部没有访问参数包的任何值,仅用到编译期确定的类型信息,所以即使传入的参数不是constexpr,整个表达式依然是合法的常量表达式,可以正常用于static_assert - 兼容你原有
myFunctionHelper的全部校验逻辑,不需要做额外修改
不修改原有myFunction签名的替代方案
如果你不想改动原有 myFunction 的定义,可以用类型列表萃取的方式实现:
// 原有代码保持不变 template<std::size_t N, class T, class... Ts> constexpr bool myFunctionHelper(const char (&fmt)[N], std::size_t n); template <std::size_t N, typename... Ts> constexpr bool myFunction(const char (&fmt)[N]) { return myFunctionHelper<N, Ts...>(fmt, 0); } // 新增辅助逻辑 template <typename... Ts> struct TypeList {}; // 从参数包提取类型生成TypeList,仅用于类型推导 template <typename... Ts> constexpr TypeList<Ts...> MakeTypeList(Ts&&...) { return {}; } // 特化实现类型包展开 template <std::size_t N, typename T> struct DispatchMyFunction; template <std::size_t N, typename... Ts> struct DispatchMyFunction<N, TypeList<Ts...>> { static constexpr bool Exec(const char (&fmt)[N]) { return myFunction<N, Ts...>(fmt); } }; // 宏定义 #define FNC(fmt, ...) \ do { \ static_assert(DispatchMyFunction<sizeof(fmt), decltype(MakeTypeList(__VA_ARGS__))>::Exec(fmt), \ "Incorrect arg types"); \ } while (false)
内容的提问来源于stack exchange,提问作者Arjun Mehta
相关产品推荐
相关产品推荐

