如何通过可变参数包初始化类中模板化的std::map成员?
问题与解决方案
问题描述
现有类A定义如下:
class A { public: template <int X> void foo(double param); const std::map<int, std::function<void(double)>> foo_map; };
需要在构造函数初始化列表中,为foo_map填充多个<整数, lambda>键值对,每个lambda会调用对应整数模板参数的foo方法,示例初始化方式如下:
A::A() : foo_map{ {2, [this](double p) { foo<2>(p); } }, {6, [this](double p) { foo<6>(p); } }, // 更多类似项 } {}
希望编写一个可变参数模板助手函数,仅传入类对象指针和整数列表即可创建该map,让构造函数可以这样初始化:
A::A() : foo_map{make_foo_map(this, 2, 6, /* 其他整数 */)} {}
尝试的助手函数代码如下,但编译器报错,提示找不到匹配的A::foo<args>(p)函数调用:
template <typename... Args> std::map<int, std::function<void(double)>> make_foo_map(A* obj, Args&&... args) { return std::map<int, std::function<void(double)>>{ {args, [obj,args](double p) { obj->foo<args>(p); }}... }; }
错误原因
函数参数args是运行时变量,而foo<X>的模板参数X必须是编译期常量,编译器无法将运行时的args作为模板参数使用,因此报错。
解决方案
将整数列表作为模板参数传递给助手函数,确保每个值都是编译期已知的常量。以下是两种可行实现:
方案1:整数可变模板参数(C++11及以上)
// 助手函数:模板参数为编译期整数序列 template<int... Ns> std::map<int, std::function<void(double)>> make_foo_map(A* obj) { // 折叠表达式展开每个整数,生成对应的键值对 return std::map<int, std::function<void(double)>>{ {Ns, [obj](double p) { obj->foo<Ns>(p); }}... }; }
构造函数中调用方式:
A::A() : foo_map(make_foo_map<2, 6, 10, /* 其他需要的整数 */>(this)) {}
方案2:auto模板参数(C++20及以上)
利用C++20的auto模板参数,支持更灵活的编译期常量类型(这里限制为int):
#include <type_traits> template<auto... Ns> // 约束所有模板参数为int类型 requires (std::is_same_v<decltype(Ns), int> && ...) std::map<int, std::function<void(double)>> make_foo_map(A* obj) { return std::map<int, std::function<void(double)>>{ {static_cast<int>(Ns), [obj](double p) { obj->foo<static_cast<int>(Ns)>(p); }}... }; }
调用方式和方案1一致:
A::A() : foo_map(make_foo_map<2, 6>(this)) {}
这两种方案都能让编译器在编译期确定每个foo<X>的模板参数,完美匹配原需求。
内容的提问来源于stack exchange,提问作者user1470475
相关产品推荐
相关产品推荐

