Skip to main content
 首页 » 编程设计

c++之如何将编译时 std::array "expand"放入参数包中

2025年12月25日42开发

我想使用部分模板特化来将数组(在编译时创建)“分解”为由其值组成的参数包(与我在代码中定义的其他结构交互)。以下(我的第一次尝试)未编译

#include <array> 
 
template <typename T, auto k> struct K; 
template <typename T, std::size_t... A> struct K<T, std::array<std::size_t, sizeof...(A)>{A...}> {}; 

因为模板参数 std::array<long unsigned int, sizeof... (A)>{A ...} must not involve template parameters .据我了解,如果非类型参数非常依赖模板参数,则不可能在部分模板特化中提供非类型参数。因此,我尝试通过在类型中包含值来解决此问题:

#include <array> 
 
template <auto f> struct any_type; 
 
template <typename T, typename array_wrapper> struct FromArr; 
template <typename T, std::size_t... A> 
struct FromArr<T, any_type<std::array<std::size_t, sizeof...(A)>{A...}>> {}; 
 
int main() { 
  FromArr<int, any_type<std::array<std::size_t, 2>{1, 2}>> d; 
  (void) d; 
} 

但是,在这里,当我尝试使用它时,部分模板特化失败了;上面的定义与我使用它的方式不匹配,我不确定为什么。它失败并出现以下错误:
file.cc: In function ‘int main()’: 
file.cc:10:55: error: aggregate ‘FromArr<int, Any<std::array<long unsigned int, 2>{std::__array_traits<long unsigned int, 2>::_Type{1, 2}}> > d’ has incomplete type and cannot be defined 
  10  |   FromArr<int, Any<std::array<std::size_t, 2>{1, 2}>> d; 

是否可以解决这个问题/使用不同的方法将数组作为参数包进行接口(interface)?

使用的编译器

我用 g++-10.0 (GCC) 10.0.1 20200124 (experimental)并通过 g++ -std=c++2a file.cc 编译, c++2a 是必需的,因为我使用非类型模板参数。

编辑:

描述如何处理数组

在我的真实代码中,我有一个结构,它依赖于——除其他外——一个参数包(1)。如果我能够使用数组 (2)(我在另一段代码中将其作为非类型模板参数)与该结构交互,那就太好了,如下面的代码所示。

template <int... s> struct toBeUsed;                               // (1) 
template <std::size_t s, std::array<int, s> arr> struct Consumer { // (2) 
    toBeUsed<arr> instance; // This is what I would like to do 
} 

我的尝试是编写一个如上的辅助结构 FromStruct ,我可以用 array 实例化它其中我有一个 typedef FromStruct::type提供 toBeUsed使用正确的参数,类似于 this example ,它用 std::tuple 所组成的类型来做我想做的事情。

链接到示例

here我链接了简化的使用示例(第二个代码块)。

请您参考如下方法:

受@dfri 回答的启发,我将她/他的解决方案转换为可以省略函数的版本,而是仅使用一个结构,使用部分模板专门化来处理 std::integer_sequence这对其他人也可能很有趣:

template <auto arr, template <typename X, X...> typename Consumer, 
          typename IS = decltype(std::make_index_sequence<arr.size()>())> struct Generator; 
 
template <auto arr, template <typename X, X...> typename Consumer, std::size_t... I> 
struct Generator<arr, Consumer, std::index_sequence<I...>> { 
  using type = Consumer<typename decltype(arr)::value_type, arr[I]...>; 
}; 

完整的用法示例:

#include <array> 
 
/// Structure which wants to consume the array via a parameter pack. 
template <typename StructuralType, StructuralType... s> struct ConsumerStruct { 
  constexpr auto operator()() const { return std::array{s...}; } 
}; 
 
/// Solution 
template <auto arr, template <typename X, X...> typename Consumer, 
          typename IS = decltype(std::make_index_sequence<arr.size()>())> struct Generator; 
 
template <auto arr, template <typename X, X...> typename Consumer, std::size_t... I> 
struct Generator<arr, Consumer, std::index_sequence<I...>> { 
  using type = Consumer<typename decltype(arr)::value_type, arr[I]...>; 
}; 
 
/// Helper typename 
template <auto arr, template <typename T, T...> typename Consumer> 
using Generator_t = typename Generator<arr, Consumer>::type; 
 
// Usage 
int main() { 
  constexpr auto tup = std::array<int, 3>{{1, 5, 42}}; 
  constexpr Generator_t<tup, ConsumerStruct> tt; 
  static_assert(tt() == tup); 
  return 0; 
}