创建具有给定尺寸的n维向量

创建具有给定尺寸的n维向量

问题描述:

所以,我想要的是创建给定类型的多维向量,其中第一个维度将具有函数调用的第一个参数的大小,例如,如果我做

So, what I want is to create multidimensional vector of given type where the first dimension will have size of the first argument of a function call, etc, for example if I do

std::size_t n = 5;
auto x = make_vector<int>(n + 1, n * 2, n * 3);

x 应为6x10x15的三维数组因为我现在想要默认构造)

x should be 6x10x15 3d array (consisting of zeroes, because I want to default construct right now)

我尝试过:

template <typename T>
std::vector<T> make_vector(std::size_t size) {
    return std::vector<T>(size);
}

template <typename T, typename... Args>
auto make_vector(std::size_t first, Args... sizes) -> std::vector<decltype(make_vector<T>(sizes...))> {
    auto inner = make_vector<T>(sizes...);
    return std::vector<decltype(inner)>(first, inner);
}

它似乎适用于1或2个参数,以下错误(clang ++)

It seems to work for 1 or 2 arguments, but fails for 3 arguments with following error(clang++)

In file included from /Users/riad/ClionProjects/for-jhelper/output/run.cpp:1:
/Users/riad/ClionProjects/for-jhelper/tasks/TaskC.cpp:12:12: error: no matching function for call to 'make_vector'
                auto x = make_vector<int>(n + 1, n * 2, n * 3);
                         ^~~~~~~~~~~~~~~~
/Users/riad/ClionProjects/for-jhelper/tasks/../spcppl/make_vector.hpp:9:6: note: candidate template ignored: substitution failure [with T = int, Args = <unsigned long, unsigned long>]: call to function 'make_vector' that is neither visible in the template definition nor found by argument-dependent lookup
auto make_vector(std::size_t first, Args... sizes) -> std::vector<decltype(make_vector<T>(sizes...))> {
     ^                                                                     ~~~~~~~~~~~
/Users/riad/ClionProjects/for-jhelper/tasks/../spcppl/make_vector.hpp:4:16: note: candidate function template not viable: requires single argument 'size', but 3 arguments were provided
std::vector<T> make_vector(std::size_t size) {



如果我理解正确的问题是当编译器试图计算make_vector的返回值它必须知道具有较少参数数的向量的返回值,并且没有这样做。如何解决这个问题?

If I understand correctly problem is that when compiler tries to calculate return value of make_vector it have to know the return value of vector with less number of arguments and fails to do so. How do I fix that?

创建一个命名空间,在其中加入一些帮助函数 details

Create a namespace to put some helpers in it, called details.

详细信息创建一个类型 struct adl_helper {};

创建 make_vector 的实现,除了它的第一个参数总是一个模板参数 Adl 。此模板参数从未命名,并且将其实例传递给递归。

Create an implementation of make_vector, except its first parameter is always a template parameter called Adl. This template parameter is never named, and instances of it are passed to recursions.

实现 make_vector(blah)调用 details :: make_vector< T>(详情:: adl_helper {},blah)

namespace details {
  struct adl_helper { };

  template <class T, class Adl>
  std::vector<T> make_vector(Adl, size_t size) {
    return std::vector<T>(size);
  }

  template <class T, class Adl, class... Args,
    class R_T=decltype(
      make_vector<T>(Adl{}, std::declval<Args>()...)
    ),
    class R=std::vector<R_T>
  >
  R make_vector(Adl, size_t first, Args... sizes) 
  {
    auto inner = make_vector<T>(Adl{}, std::forward<Args>(sizes)...);
    return R(first, inner);
  }
}


template <class T, class... Args,
  class R=decltype(
    details::make_vector<T>(details::adl_helper{}, std::declval<Args>()...)
  )
>
R make_vector(Args... args)
{
  return details::make_vector<T>(details::adl_helper{}, std::forward<Args>(args)...);
}

这里发生的是一个看似递归的调用模板函数在两个上下文中进行评估。

What is going on here is that a seemingly recursive call in the signature of a template function is evaluated in two contexts.

首先,评估它被声明的位置。特别地,在它自己被定义之前对其进行评估。因此,它不会捕获自身。

First, it is evaluated where it is declared. In particular, it is evaluated before itself has been defined. So it doesn't "catch" itself.

其次,基于ADL(参数依赖查找)的传递是在仅基于模板类型传递给函数。

Second, an ADL (argument dependent lookup) based pass is done at the point where it is instantiated based only off template types passed to the function.

模板< class Adl> adl_helper types意味着这个参数依赖的查找在实例化时可以看到 detail :: make_vector 函数本身。当查找返回类型时,还可以 看到 details :: make_vector 。 Etc。

The template<class Adl> and adl_helper types means that this argument dependent lookup can see the details::make_vector function itself when it is instantiated. And when it looks up the return type, it can also see details::make_vector. Etc.

实例

使用 class R = 别名等只是为了清除代码并减少一些不必要的重复。

The use of class R= aliases and the like is just there to cleanup the code and reduce some needless duplication.

在这种特殊情况下,构建返回类型所需的努力比所有这些体操更容易。

In this particular case, the effort required to build the return type is easier than all this gymnastics.

我认为此解决方案更干净

template<class T>struct tag{using type=T;};
template<class Tag>using type=typename Tag::type;

template<class T, size_t n>
struct n_dim_vec:tag< std::vector< type< n_dim_vec<T, n-1> > > > {};
template<class T>
struct n_dim_vec<T, 0>:tag<T>{};
template<class T, size_t n>
using n_dim_vec_t = type<n_dim_vec<T,n>>;