如何避免初始化可变模板构造的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; }
关键说明
- 模板构造函数:新增的模板构造函数接受
std::index_sequence<Is...>,其中Is...的数量和LevelType(即tuple)的元素个数一致。通过(static_cast<void>(Is), data)...展开参数包——逗号表达式先执行无意义的static_cast<void>(Is)占位,再返回data,最终展开成对应次数的data实参,完美匹配tuple的构造需求。 - 对外封装:对外暴露的构造函数不需要用户处理索引序列,自动调用
std::make_index_sequence<std::tuple_size_v<LevelType>>生成对应长度的序列,用户只需要传一次data。 - 编译期支持:给
Level和Tree的构造函数加上constexpr,确保可以在编译期构造Tree对象(示例中LevelData是空类,天然满足constexpr要求)。
内容的提问来源于stack exchange,提问作者Astor
相关产品推荐
相关产品推荐

