Templates 如何在N维矩阵中的位置映射到1D,在编译时C++?

Templates 如何在N维矩阵中的位置映射到1D,在编译时C++?,templates,matrix,c++17,variadic-templates,template-meta-programming,Templates,Matrix,C++17,Variadic Templates,Template Meta Programming,在编译期间,我必须计算元素在一维数组中的n维矩阵中的位置。 简而言之,数组[i][j][k]..[n]>array[…]的映射,其中i,j,k,…,n在{1,2,3}中,并且每个索引的维数为DIM=3。也就是说,每行和每列有3个元素 我的主要问题是编写n个索引参数包的总和作为模板,并在编译时使用constexpr计算总和 我在其他stack post中的研究得出以下三维公式: a[i][j][k] -> a[(i*DIM*DIM) + (j*DIM) + k] 如果我们将其展开为

在编译期间,我必须计算元素在一维数组中的n维矩阵中的位置。 简而言之,数组[i][j][k]..[n]>array[…]的映射,其中i,j,k,…,n在{1,2,3}中,并且每个索引的维数为DIM=3。也就是说,每行和每列有3个元素

我的主要问题是编写n个索引参数包的总和作为模板,并在编译时使用constexpr计算总和

我在其他stack post中的研究得出以下三维公式:

    a[i][j][k] -> a[(i*DIM*DIM) + (j*DIM) + k]
如果我们将其展开为n维,则会得到以下公式:

    a[i][j][k]....[n] -> a[(n*DIM ^ (indexAmount-1)] +... + (i*DIM*DIM) + (j*DIM) + k].
此外,我编写了使用模板和constexpr生成和的加数的代码,如下面的代码所示

    /**
    * calculates DIM3^(indexPos)
    */
    template<auto count>
    int constexpr multiple_dim(){
        if constexpr (count == 0){
            return 1;
        }else{
            return DIM3 * multiple_dim<count-1>();
        }
    }

    /**
    *
    *calculates addends for the end summation
    * e.g if we have 3 indices i,j,k. j would be at position 2
    * and j = 1. The parameters would be IndexPos = 2, index = 1.

    */
    template<auto indexPos, auto index>
    int constexpr calculate_flattened_index(){
        if constexpr (indexPos == 0){
            return (index-1);
        }else{
            return (index-1) * multiple_dim<indexPos>();
        }
    }

    /**
     * calculates the position of an element inside a
     * nD matrix and maps it to a position in 1D
     * A[i][j]..[n] -> ???? not implemented yet
     * @tparam Args
     * @return
     */
    template<auto ...Args>
    [[maybe_unused]] auto constexpr pos_nd_to_1d(){
     /* maybe iterate over all indices inside the parameter pack?
        const int count = 1;
        for(int x : {Args...}){

        }
        return count;
    */
    }
所需的输出可能类似于以下代码:

函数调用

    pos_nd_to_1d<1,1,1>() //A111 
    pos_nd_to_1d<1,2,1>() //A121 
    pos_nd_to_1d<1,3,1>() //A131 

如果我理解正确。。。你的表情如下

template <auto ... as>
auto constexpr pos_nd_to_1d ()
 { 
   std::size_t  i { 0u };

   ((i *= DIM, i += as - 1u), ...);

   return i;
 }
但对于指数,我建议使用std::size\t,也可以使用std::size\t。。。作为

下面是一个完整的编译示例

#include <iostream>

constexpr auto DIM = 3u;

template <auto ... as>
auto constexpr pos_nd_to_1d ()
 { 
   std::size_t  i { 0u };

   ((i *= DIM, i += as - 1u), ...);

   return i;
 }


int main ()
 {
   std::cout << pos_nd_to_1d<1u, 1u, 1u>() << std::endl;
   std::cout << pos_nd_to_1d<1u, 2u, 1u>() << std::endl;
   std::cout << pos_nd_to_1d<1u, 3u, 1u>() << std::endl;
 }
被称为或也被称为折叠或模板折叠,这是一个新的C++17功能您也可以在C++14和C++11中获得相同的结果,但不是constexpr,而是以一种不太简单和优雅的方式,包括使用运算符展开可变模板包

举例来说,如果您想对索引求和,只需编写

(as + ...);
这个表达变成了

(a0 + (a1 + (a2 + (/* etc */))));
在本例中,我使用了逗号是运算符这一事实,因此表达式

   ((i *= DIM, i += as - 1u), ...);
变成

   ((i *= DIM, i += a0 - 1u), 
     ((i *= DIM, i += a1 - 1u),
        ((i *= DIM, i += a2 - 1u),
           /* etc. */ )))))
通过这种方式可以观察到,第一个i*=DIM是无用的,因为i被初始化为零,但是下面的i*=DIM乘以-1u的次数是正确的

所以,当。。。是1,2,1,举例来说,你得到

  (1 - 1)*DIM*DIM + (2 - 1)*DIM + (1 - 1)

如果你有一些空闲时间,你能解释一下这个代码是如何工作的吗?我有点新到C++ + .M.Mac -答案的改进;希望这有帮助。
(a0 + (a1 + (a2 + (/* etc */))));
   ((i *= DIM, i += as - 1u), ...);
   ((i *= DIM, i += a0 - 1u), 
     ((i *= DIM, i += a1 - 1u),
        ((i *= DIM, i += a2 - 1u),
           /* etc. */ )))))
  (1 - 1)*DIM*DIM + (2 - 1)*DIM + (1 - 1)