如何将std::tuple的元素展开作为模板类的非类型模板参数?
如何将std::tuple的元素展开作为模板类的非类型模板参数?
嘿,我来给你拆解这个问题的解决思路~
首先咱们先理清楚你遇到的场景:你定义了一个用auto...作为非类型模板参数的foo类模板:
template<auto...m> struct foo {};
直接用单个或多个字面量初始化foo完全没问题,比如foo<1>{};或者foo<'a',1>{};都能正常编译。但如果想把一个constexpr的std::tuple直接传进去,比如这样:
constexpr auto t1 = std::make_tuple('a',1); foo<t1> {};
编译器就会报错——这是因为std::tuple不属于C++规定的结构化类型,没法直接作为非类型模板参数使用。
那怎么把tuple里的元素逐个拆出来传给foo呢?咱们可以借助编译期的索引序列来实现,具体看下面的代码示例:
#include <tuple> #include <utility> // 用于std::index_sequence和std::make_index_sequence template<auto...m> struct foo {}; // 辅助实现:通过索引序列取出tuple的每个元素 template<auto Tuple, std::size_t... I> constexpr auto make_foo_impl(std::index_sequence<I...>) { return foo<std::get<I>(Tuple)...>{}; } // 对外接口:自动生成对应tuple大小的索引序列 template<auto Tuple> constexpr auto make_foo() { return make_foo_impl<Tuple>(std::make_index_sequence<std::tuple_size_v<decltype(Tuple)>>{}); } int main() { constexpr auto t1 = std::make_tuple('a', 1); // 这里得到的就是foo<'a', 1>的实例 constexpr auto f = make_foo<t1>(); }
我给你唠唠这个逻辑:
- 首先,
std::tuple_size_v<decltype(Tuple)>会在编译期算出tuple的元素个数; - 然后
std::make_index_sequence会生成一个从0到元素个数-1的索引序列(比如这里就是0,1); - 接着在
make_foo_impl里,我们用std::get<I>(Tuple)逐个取出tuple里的元素,把这些元素作为参数传递给foo模板,相当于手动把'a'和1拆出来传给foo。
这样就绕开了直接传tuple作为非类型参数的限制,间接实现了把tuple的元素展开成foo的非类型模板参数。
要注意哦,这个方法要求tuple里的每个元素本身都是可以作为非类型模板参数的类型(比如字面量类型:整数、字符、指针/引用到静态对象等),如果tuple里有不满足的类型,那还是没法用的~
备注:内容来源于stack exchange,提问作者abcdefg
相关产品推荐
相关产品推荐

