如何使用可变参数模板初始化constexpr类静态成员?
解决可变参数模板初始化constexpr类成员的问题
你的代码编译失败的核心原因是误用了折叠表达式写法:{( tp_params::val(), ... )} 展开后会变成一个逗号表达式(比如针对test<A,B>,展开结果是(A::val(), B::val())),最终初始化列表里仅存在一个值(逗号表达式的结果为最后一个元素的值),但std::array的大小是2,导致初始化元素数量不匹配,而非单纯的常量表达式合规性问题。
可行解决方法
直接在初始化列表中展开参数包即可,C++17及以上标准支持这种简洁写法:
#include <array> #include <cstdint> class A { public: static constexpr int val() { return 20; } }; class B { public: static constexpr int val() { return 30; } }; template<class... tp_params> class test { protected: static constexpr uint32_t count = sizeof...(tp_params); // 直接展开参数包,每个tp_params::val()作为array的独立元素 static constexpr std::array<int, count> m_values = { tp_params::val()... }; }; // 验证代码 int main() { constexpr auto& vals = test<A, B>::m_values; static_assert(vals[0] == 20); static_assert(vals[1] == 30); return 0; }
原理说明
tp_params::val()...会将参数包中的每个类型依次展开,生成对应的val()调用,作为std::array初始化列表的元素,完美匹配array的大小。- C++17及以上标准允许
static constexpr的std::array直接在类内完成初始化,无需额外的类外定义。
如果需要兼容C++14,可以借助std::index_sequence实现类似功能:
#include <array> #include <cstdint> #include <utility> #include <tuple> class A { public: static constexpr int val() { return 20; } }; class B { public: static constexpr int val() { return 30; } }; template<class... tp_params, std::size_t... Idx> constexpr std::array<int, sizeof...(tp_params)> make_values(std::index_sequence<Idx...>) { return { (std::tuple_element_t<Idx, std::tuple<tp_params...>>::val())... }; } template<class... tp_params> class test { protected: static constexpr uint32_t count = sizeof...(tp_params); static constexpr std::array<int, count> m_values = make_values<tp_params...>(std::make_index_sequence<count>{}); }; // 验证代码 int main() { constexpr auto& vals = test<A, B>::m_values; static_assert(vals[0] == 20); static_assert(vals[1] == 30); return 0; }
内容的提问来源于stack exchange,提问作者bantpro
相关产品推荐
相关产品推荐

