n维数组构造函数的模板规范

时间:2020-12-26 21:42:44

I am implementing an n-dimensional array class which is a template as follows (Note that the data is stored in a linear array whose length is the product of all the dimensions):

我正在实现一个n维数组类,它是一个模板如下(请注意,数据存储在一个线性数组中,其长度是所有维度的乘积):

template< class valType, int rank >
class NDimensionalArray
{
public:

private:
    valType* m_data;
    int* m_dimensions;
    int m_rank;
};

So the idea is that a user (me) can specify an array of rank 2, and of a certain dimension, ie:

所以我的想法是用户(我)可以指定排名2和某个维度的数组,即:

NDimensionalArray<double,2> matrix(10,10);

Now the difficulty is in specializing constructors for 1->n dimensions, each constructor takes n parameters where n is the rank of the array. Now I thought of using a valarray like is used in printf(), however with this defining a 1-dimensional array with 2 dimensions ie:

现在困难在于专门构造1-> n维的构造函数,每个构造函数需要n个参数,其中n是数组的等级。现在我想到使用像printf()中使用的valarray,但是这个定义了一个具有2维的1维数组,即:

NDimensionalArray<double,1> matrix(10,10);

would be perfectly acceptable behavior. Is there some neat trick I can use to let the compiler do the repetition? Realistically so long as I know the rank, and have the length of each dimension the constructor can be generic:

是完全可以接受的行为。我可以使用一些巧妙的技巧让编译器重复吗?实际上只要我知道排名,并且具有每个维度的长度,构造函数就可以是通用的:

{
    int nElements = m_dimensions[0];
    for ( int i=1 ; i<m_rank ; ++i )
        nElements *= m_dimensions[i];
    m_data = new valType[nElements];
}

Edit: Note that a similar operation will be needed for accessors.

编辑:请注意,访问者将需要类似的操作。

Also I have considered the option of a constructor which looks like:

此外,我已经考虑了一个构造函数的选项,看起来像:

NDimensionalArray( const NDimensionalArray<int,1>& dimensions );

Which could be used like:

可以使用如下:

NDimensionalArray<int,1> dimVec(2); // Need a specification for 1-dimensional arrays.
dimVec(0) = 10;
dimVec(1) = 10;
NDimensionalArray<double,2> matrix(dimVec);

This would be a viable solution, but its ugly compared to the use I would like. Also accessing multi-dimensional arrays would become a serious pain, and seriously slow having to construct a dimension vector for each access.

这将是一个可行的解决方案,但与我想要的用途相比它很难看。访问多维数组也会变得非常痛苦,并且必须为每次访问构建维度向量非常慢。

6 个解决方案

#1


Okay, I've played with this for a while. Here's some template metaprogramming hackery that does something close to what you want. It lets you specify all dimensions inline, it doesn't do any dynamic memory allocation or other such things. In addition, with a good C++ compiler (I tested with VC++ /O2 option), the code will be fully inlined, with no copies done (in fact, for me it inlined the whole NDimensionalArray constructor at the point of the call). It will typecheck completely at compile-time, and won't let you pass too few or too many dimensions. And it can be reused for indexers. Here goes:

好的,我已经玩了一段时间了。这是一些模板元编程hackery,它可以完成你想要的东西。它允许您指定内联的所有维度,它不执行任何动态内存分配或其他此类事情。另外,使用一个好的C ++编译器(我用VC ++ / O2选项测试),代码将完全内联,没有完成复制(事实上,对我来说,它在调用时内联整个NDimensionalArray构造函数)。它会在编译时完全进行类型检查,并且不会让你传递太少或太多的维度。它可以重复用于索引器。开始:

template<class T, int N>
class value_pack : private value_pack<T, N-1>
{
public:

    enum { size = N };

    value_pack(value_pack<T, N-1> head, const T& tail)
        : value_pack<T, N-1>(head)
        , value(tail)
    {
    }

    value_pack<T, N+1> operator() (const T& tail) const
    {
        return value_pack<T, N+1>(*this, tail);
    }

    template<int I>
    const T& get() const
    {
        return this->value_pack<T, I+1>::value;
    }

protected:

    const T value;
};

template<class T>
struct value_pack<T, 0>
{
};

struct
{
    template <class T>
    value_pack<T, 1> operator() (const T& tail) const
    {
        return value_pack<T, 1>(value_pack<T, 0>(), tail);
    }
} const values;


template <class ValType, int Rank>
struct NDimensionalArray
{
    NDimensionalArray(value_pack<ValType, Rank> values)
    {
        // ...
    }
};


int main()
{
    NDimensionalArray<int, 3> a(values(1)(2)(3));
}

#2


I think the best solution is to take a vector of ints and let the constructor validate it against the template parameter 'rank'.

我认为最好的解决方案是采用一个int的向量,让构造函数根据模板参数'rank'验证它。

NDimensionalArray matrix(std::vector<int> matrixDimensions) 
{
    if (matrixDimensions.size() != rank) 
    {
        throw SomeException();
    }

    ...
}

I don't think any compiler trick can be an alternative here. (Except perhps using macros, if you can think of something, although that wouldn't be a compiler trick strictly speaking.)

我认为任何编译器技巧都不能成为替代方案。 (除了使用宏的perhps,如果你能想到某些东西,尽管严格来说这不是编译技巧。)

#3


Not a direct answer, but check out the blitz library.

不是直接的答案,但看看闪电战库。

#4


There's no good way to do it in C++ as currently standardized. In C++0x, you'll be able to use template parameter packs to approximate (I think I've got the syntax right, but not sure about expansion in requires):

目前在标准化的C ++中没有好办法。在C ++ 0x中,您将能够使用模板参数包进行近似(我认为我的语法正确,但不确定需要扩展):

template <class ValType, int Rank>
struct NDimensionalArray
{
    template <class... Args>
    requires std::SameType<Args, ValType>... && std::True<sizeof...(Args) == Rank>
    NDimensionalArray(Args... values)
    {
        ...
    }
};

#5


You could take a std::tr1::array. Hmm:

你可以采用std :: tr1 :: array。嗯:

#include <array>

template< class valType, int rank >
class NDimensionalArray
{
public:
   NDimensionalArray(const std::tr1::array<rank>& dims);
   // ...
};

NDimensionalArray<double,2> foo({10,10});

NDimensionalArray<double,2> bar({10}); // second dimension would be 0

NDimensionalArray<double,1> baz({10,10}); // compile error?

I'm not actually sure if that works! I'll run it through comeau.

我真的不确定这是否有效!我会通过考虑来运行它。

Edited As per the comments, looks like this approach would look more like:

编辑根据评论,看起来这种方法看起来更像:

std::tr1::array<2> dims = {10, 10};
NDimensionalArray<double,2> foo(dims);

#6


Boost has a multi-array library that uses a custom object for constructing their multidimensional array. It's a really good way to do it; I suggest you study (or better yet, use) their code.

Boost有一个多数组库,它使用自定义对象来构造它们的多维数组。这是一个非常好的方法;我建议你学习(或者更好,使用)他们的代码。

#1


Okay, I've played with this for a while. Here's some template metaprogramming hackery that does something close to what you want. It lets you specify all dimensions inline, it doesn't do any dynamic memory allocation or other such things. In addition, with a good C++ compiler (I tested with VC++ /O2 option), the code will be fully inlined, with no copies done (in fact, for me it inlined the whole NDimensionalArray constructor at the point of the call). It will typecheck completely at compile-time, and won't let you pass too few or too many dimensions. And it can be reused for indexers. Here goes:

好的,我已经玩了一段时间了。这是一些模板元编程hackery,它可以完成你想要的东西。它允许您指定内联的所有维度,它不执行任何动态内存分配或其他此类事情。另外,使用一个好的C ++编译器(我用VC ++ / O2选项测试),代码将完全内联,没有完成复制(事实上,对我来说,它在调用时内联整个NDimensionalArray构造函数)。它会在编译时完全进行类型检查,并且不会让你传递太少或太多的维度。它可以重复用于索引器。开始:

template<class T, int N>
class value_pack : private value_pack<T, N-1>
{
public:

    enum { size = N };

    value_pack(value_pack<T, N-1> head, const T& tail)
        : value_pack<T, N-1>(head)
        , value(tail)
    {
    }

    value_pack<T, N+1> operator() (const T& tail) const
    {
        return value_pack<T, N+1>(*this, tail);
    }

    template<int I>
    const T& get() const
    {
        return this->value_pack<T, I+1>::value;
    }

protected:

    const T value;
};

template<class T>
struct value_pack<T, 0>
{
};

struct
{
    template <class T>
    value_pack<T, 1> operator() (const T& tail) const
    {
        return value_pack<T, 1>(value_pack<T, 0>(), tail);
    }
} const values;


template <class ValType, int Rank>
struct NDimensionalArray
{
    NDimensionalArray(value_pack<ValType, Rank> values)
    {
        // ...
    }
};


int main()
{
    NDimensionalArray<int, 3> a(values(1)(2)(3));
}

#2


I think the best solution is to take a vector of ints and let the constructor validate it against the template parameter 'rank'.

我认为最好的解决方案是采用一个int的向量,让构造函数根据模板参数'rank'验证它。

NDimensionalArray matrix(std::vector<int> matrixDimensions) 
{
    if (matrixDimensions.size() != rank) 
    {
        throw SomeException();
    }

    ...
}

I don't think any compiler trick can be an alternative here. (Except perhps using macros, if you can think of something, although that wouldn't be a compiler trick strictly speaking.)

我认为任何编译器技巧都不能成为替代方案。 (除了使用宏的perhps,如果你能想到某些东西,尽管严格来说这不是编译技巧。)

#3


Not a direct answer, but check out the blitz library.

不是直接的答案,但看看闪电战库。

#4


There's no good way to do it in C++ as currently standardized. In C++0x, you'll be able to use template parameter packs to approximate (I think I've got the syntax right, but not sure about expansion in requires):

目前在标准化的C ++中没有好办法。在C ++ 0x中,您将能够使用模板参数包进行近似(我认为我的语法正确,但不确定需要扩展):

template <class ValType, int Rank>
struct NDimensionalArray
{
    template <class... Args>
    requires std::SameType<Args, ValType>... && std::True<sizeof...(Args) == Rank>
    NDimensionalArray(Args... values)
    {
        ...
    }
};

#5


You could take a std::tr1::array. Hmm:

你可以采用std :: tr1 :: array。嗯:

#include <array>

template< class valType, int rank >
class NDimensionalArray
{
public:
   NDimensionalArray(const std::tr1::array<rank>& dims);
   // ...
};

NDimensionalArray<double,2> foo({10,10});

NDimensionalArray<double,2> bar({10}); // second dimension would be 0

NDimensionalArray<double,1> baz({10,10}); // compile error?

I'm not actually sure if that works! I'll run it through comeau.

我真的不确定这是否有效!我会通过考虑来运行它。

Edited As per the comments, looks like this approach would look more like:

编辑根据评论,看起来这种方法看起来更像:

std::tr1::array<2> dims = {10, 10};
NDimensionalArray<double,2> foo(dims);

#6


Boost has a multi-array library that uses a custom object for constructing their multidimensional array. It's a really good way to do it; I suggest you study (or better yet, use) their code.

Boost有一个多数组库,它使用自定义对象来构造它们的多维数组。这是一个非常好的方法;我建议你学习(或者更好,使用)他们的代码。