You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过可变参数包初始化类中模板化的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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.18 14:37:19