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

如何避免初始化可变模板构造的Level tuple时重复传入data参数?

问题

此前我曾提问类似问题但未修改原问题,在此致歉。我有一个构造函数需传入参数的Level类,通过可变模板为Tree类的成员创建了一个由Level类型组成的tuple类型LevelType。如何在Tree的初始化列表中避免重复传入data值?额外约束:Tree对象需支持编译时构造,因此需要借助模板元编程技巧。

原代码片段:

#include<utility>
#include<array>
#include<iostream>

class LevelData
{};

template <typename LevelType>
class Level
{            
    public:
    Level(LevelData & data_):
    data(data_)
    {};

    LevelData & data ;
};

template <std::size_t nLevels,typename LevelType>
class Tree
{            
    public:
    Tree(LevelData & data):
    level(data,data,data,data,data)
    {};

    LevelType level ;                                                                        
};

template <std::size_t nLevels,auto... Is>
auto make_tree_impl(std::index_sequence<Is...>)
    -> Tree<nLevels,std::tuple<Level<std::array<double, std::size_t{1} << Is>>...>>;

template <std::size_t nLevels>
using make_tree = decltype(make_tree_impl<nLevels>(std::make_index_sequence<nLevels>{}));

int main()
{
    const unsigned int nLevels = 5;
    LevelData data;
    auto tree = make_tree<nLevels>(data);
    std::cout << std::is_same<decltype(tree),
    Tree<nLevels,std::tuple<Level<std::array<double,1>>,
                            Level<std::array<double,2>>,
                            Level<std::array<double,4>>,
                            Level<std::array<double,8>>,
                            Level<std::array<double,16>>>>>::value << std::endl ;
    return 0;
}
解决方案

核心是利用参数包展开结合std::index_sequence,自动生成对应次数的data实参,同时保证编译期构造能力。

修改后代码

#include<utility>
#include<array>
#include<iostream>

class LevelData
{};

template <typename LevelType>
class Level
{            
public:
    constexpr Level(LevelData& data_) : data(data_) {}

    LevelData& data;
};

template <std::size_t nLevels, typename LevelType>
class Tree
{            
public:
    // 内部模板构造函数:用索引序列控制展开次数
    template <std::size_t... Is>
    constexpr Tree(LevelData& data, std::index_sequence<Is...>)
        : level((static_cast<void>(Is), data)...) {}

    // 对外构造函数:自动生成对应长度的索引序列
    constexpr explicit Tree(LevelData& data)
        : Tree(data, std::make_index_sequence<std::tuple_size_v<LevelType>>{}) {}

    LevelType level;                                                                        
};

template <std::size_t nLevels, auto... Is>
auto make_tree_impl(std::index_sequence<Is...>)
    -> Tree<nLevels, std::tuple<Level<std::array<double, std::size_t{1} << Is>>...>>;

template <std::size_t nLevels>
using make_tree = decltype(make_tree_impl<nLevels>(std::make_index_sequence<nLevels>{}));

int main()
{
    constexpr unsigned int nLevels = 5;
    LevelData data;
    constexpr auto tree = make_tree<nLevels>(data); // 支持编译期构造
    std::cout << std::is_same_v<decltype(tree),
    Tree<nLevels, std::tuple<Level<std::array<double,1>>,
                            Level<std::array<double,2>>,
                            Level<std::array<double,4>>,
                            Level<std::array<double,8>>,
                            Level<std::array<double,16>>>>> << std::endl ;
    return 0;
}

关键说明

  1. 模板构造函数:新增的模板构造函数接受std::index_sequence<Is...>,其中Is...的数量和LevelType(即tuple)的元素个数一致。通过(static_cast<void>(Is), data)...展开参数包——逗号表达式先执行无意义的static_cast<void>(Is)占位,再返回data,最终展开成对应次数的data实参,完美匹配tuple的构造需求。
  2. 对外封装:对外暴露的构造函数不需要用户处理索引序列,自动调用std::make_index_sequence<std::tuple_size_v<LevelType>>生成对应长度的序列,用户只需要传一次data。
  3. 编译期支持:给Level和Tree的构造函数加上constexpr,确保可以在编译期构造Tree对象(示例中LevelData是空类,天然满足constexpr要求)。

内容的提问来源于stack exchange,提问作者Astor

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.10 15:55:05