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