【问题标题】:How to write a function that takes a variadic number of array<double, N> and deduce N?如何编写一个函数,该函数采用数组<double,N>的可变数并推导出N?
【发布时间】:2020-12-19 13:58:42
【问题描述】:

我们的目标是有一个函数,它可以接收任意数量的任意大小 N 的数组(但这对所有人来说都是一样的),并且在函数体内有 N 可用。例如,假设我想使用 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);
}

【问题讨论】:

  • @Scheff N 应该是作为参数给出的数组的大小,而不是数组的数量。显示的代码应该只处理std::array&lt;double,3&gt;
  • 抱歉,解释不好,目标是有一个函数,它可以接收任意数量的任意大小 N 的数组(但这对所有人都可以),并且有N 在函数体内可用。例如,假设我想使用 N, MyArray 返回另一个用户定义的数组类型。我希望它更清楚!谢谢。

标签: c++ templates c++17 variadic-templates template-argument-deduction


【解决方案1】:

我不完全确定我是否理解你的函数试图做什么。我猜它是“对所有数组求和并在每个字段中添加 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);
}

【讨论】:

  • 请注意,main 在 C++ 中必须具有返回类型 int。不允许为void
  • 我已经更正了我的问题并说清楚了我希望,我会努力解决你的问题,非常感谢,那么递归是唯一的方法吗?
【解决方案2】:

我想你可以接受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()

看看什么解决方案对你更有用。

【讨论】:

  • 将数组大小的验证放在static_assert 中可能更有用。错误信息会更有意义。
  • 有没有人注意到当帖子被编辑并且帽子仍然显示在原来的位置时这个有趣的错误?
  • @FrançoisAndrieux - 嗯...我通常更喜欢 SFINAE 方式,因为您可以添加 foo()... 的替代版本...但谁知道 OP 的需求?添加了 static_assert() 替代选项。
【解决方案3】:

我终于设法做到了,仍然不好的元素是 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;
}

【讨论】:

    猜你喜欢
    • 2015-02-21
    • 2014-11-14
    • 1970-01-01
    • 2016-11-27
    • 2020-05-31
    • 1970-01-01
    • 2013-09-16
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多