如何编写一个接受数组 <double, N> 的可变数并推导 N 的函数?

How to write a function that takes a variadic number of array<double, N> and deduce N?

我们的目标是拥有一个函数,该函数接受任意数量的任意大小的数组(但这对所有数组都相同),并在函数体内提供 N。例如,假设我想 return 另一个用户定义的数组类型,使用 N,MyArray。我希望它更清楚!谢谢 我是可变参数模板的新手,不知道该怎么做。任何帮助或提示表示赞赏。谢谢

#include <array>
using namespace std;

template<int N>
struct MyArray {};

// here I don't know how to deduce N and keep the variadic number of parameters

template<int N, typename... Ts>
MyArray<N> foo(const Ts&... ts)
{ 
  // somehow use the variadic parameters
  MyArray<N> a;
  return a;
}

int main()
{
  array<double, 3> a, b, c;
  auto d = foo(a, b, c);
}

我不完全确定我是否理解您的函数要做什么。我猜它是“对所有数组求和并将 N 加到每个字段”,如果不是,无论如何我的示例应该是一个很好的说明。

template<size_t N, typename... Ts>
std::array<double, N> foo(std::array<double, N> first)
{
  for (size_t i = 0; i < N; ++i) {
    first[i] += N;
  }
  return first;
}

template<size_t N, typename... Ts>
std::array<double, N> foo(const std::array<double, N>& first, Ts&... ts)
{
  std::array<double, N> result = foo(ts...);
  for (size_t i = 0; i < N; ++i) {
    result[i] += first[i];
  }
  return result;
}

template<size_t N>
void print_array(const std::array<double, N>& arr) {
  for (double x : arr) {
    std::cout<<x<<" ";
  }
  std::cout<<"\n";
}

int main() {
  std::array<double, 3> a = {1, 2, 3};
  std::array<double, 3> b = {4, 5, 6};
  std::array<double, 3> c = {7, 8, 9};
  auto d = foo(a, b, c);
  print_array(d);
  d = foo(a, b);
  print_array(d);
}

我想你可以接受 std::array 的序列,推导尺寸,只有尺寸一致时 SFINAE 才启用该功能。

我的意思是……

template <std::size_t N0, std::size_t ... Ns,
          std::enable_if_t<((N0 == Ns) && ...), int> = 0> 
auto foo (std::array<double, N0> const & a0,
          std::array<double, Ns> const & ... as)
 { 
   std::array<double, N0> d;
   d[0] = (a0[0] + ... + as[0]);
   d[0] += N0;
   return d;
 }

template <std::size_t ... Ns, std::size_t N = (Ns + ...)/sizeof...(Ns),
          std::enable_if_t<((N == Ns) && ...), int> = 0> 
auto foo (std::array<double, Ns> const & ... as)
 { 
   std::array<double, N> d;
   d[0] = (N + ... + as[0]);
   return d;
 }

或者,如果您愿意,推导第一个大小并强加以下类型是相同的

template <std::size_t N0, typename ... Ts,
          std::enable_if_t<((std::is_same_v<std::array<double, N0>, Ts>) && ...), int> = 0> 
auto foo (std::array<double, N0> const & a0, Ts const & ... as)
 { 
   std::array<double, N0> d;
   d[0] = (a0[0] + ... + as[0]);
   d[0] += N0;
   return d;
 }

正如 François Andrieux 所指出的,您可以按照 static_assert() 的方式代替 SFINAE 方式,以获得更有意义的消息错误

template <std::size_t N0, std::size_t ... Ns> 
auto foo (std::array<double, N0> const & a0,
          std::array<double, Ns> const & ... as)
 { 
   static_assert( ((N0 == Ns) && ...), "some clear error message!");

   // ...

但是,通过这种方式,您无法开发 foo() 的不同版本和替代版本。

看看哪个解决方案对你更有用

我终于成功了,仍然不好的是 Foo 的模板部分中 N 的类型必须与 std::array 中使用的类型完全匹配以指示大小,这使得 N 已知里面,可以用来制作一个 MyArray 对象。

基本上我必须将参数包声明为一个模板(因此有一个带有模板包的模板)。 Ts... 在那里是因为数组通常需要 2 个以上的模板参数。

#include <array>
using namespace std;

template<int N>
struct MyArray {};

template<typename T, long unsigned N, typename... Ts, template<typename, long unsigned, typename...> typename... Arrays>
MyArray<N> Foo(const Arrays<T, N, Ts...>&... arrays)
{
    return MyArray<N>{};
}

int main()
{
    array<double, 3> a, b, c;

    MyArray<3> d = Foo(a, b, c);
    auto e = Foo(a, b);

    return 0;
}