templates - 如何在编译时在 C++ 中将维度矩阵中的位置映射到一维?
问题描述
我必须n
在编译期间计算一维数组内维矩阵中元素的位置。简而言之,每个索引的array[i][j][k]....[n] -> array[...]
, where i,j,k,...,n
in和维度的映射是。这意味着,每一行和每一列都有 3 个元素。{1,2,3}
DIM = 3
我的主要问题是编写n
索引(参数包)的总和,作为模板并constexpr
用于在编译时评估总和。
我在其他堆栈帖子中的研究得出了以下 3 维公式:
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].
此外,i
使用模板和 编写代码来生成和的加数,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;
*/
}
3D 矩阵中元素的示例输出A
。
A111
, A121
, A131
. 3 个元素的总和将是 1D 中的位置。例如A121 -> 0 + 3 + 0 = 3
。A111
将被放置在 的一维数组中array[3]
。
std::cout << "Matrix A111" << std::endl;
//A111
std::cout << calculate_flattened_index<0 , 1>() << std::endl;
std::cout << calculate_flattened_index<1 , 1>() << std::endl;
std::cout << calculate_flattened_index<2 , 1>() << std::endl;
std::cout << "Matrix A121" << std::endl;
//A121
std::cout << calculate_flattened_index<0 , 1>() << std::endl;
std::cout << calculate_flattened_index<1 , 2>() << std::endl;
std::cout << calculate_flattened_index<2 , 1>() << std::endl;
std::cout << "Matrix A131" << std::endl;
//A131
std::cout << calculate_flattened_index<0 , 1>() << std::endl;
std::cout << calculate_flattened_index<1 , 3>() << std::endl;
std::cout << calculate_flattened_index<2 , 1>() << std::endl;
Output:
Matrix A111
0
0
0
Matrix A121
0
3
0
Matrix A131
0
6
0
所需的输出可能类似于以下代码:
函数调用
pos_nd_to_1d<1,1,1>() //A111
pos_nd_to_1d<1,2,1>() //A121
pos_nd_to_1d<1,3,1>() //A131
输出:
0 //0+0+0
3 //0+3+0
6 //0+6+0
解决方案
如果我理解正确...您看起来如下
template <auto ... as>
auto constexpr pos_nd_to_1d ()
{
std::size_t i { 0u };
((i *= DIM, i += as - 1u), ...);
return i;
}
或者,也许您可以使用std::common_type
, for i
,
std::common_type_t<decltype(as)...> i {};
但对于索引,我建议使用std::size_t
(also std::size_t ... as
)。
下面是一个完整的编译示例
#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;
}
- 编辑 -
OP问
你能解释一下这段代码是如何工作的吗?我对 C++ 有点陌生。
无论如何,我更擅长编写代码来解释......
我在这里用过的
((i *= DIM, i += as - 1u), ...);
//...^^^^^^^^^^^^^^^^^^^^^^ repeated part
被称为“折叠表达式”(或也称为“折叠”或“模板折叠”),并且是 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
乘以as - 1u
正确的次数
所以,什么时候as...
,1, 2, 1
例如,你得到
(1 - 1)*DIM*DIM + (2 - 1)*DIM + (1 - 1)
推荐阅读
- github - 为什么某些 GitHub 操作停止执行?
- spring-data - Spring Data JDBC - 如何为仅在运行时知道的实体提供动态数据库模式?
- python - 返回列表中小于其索引的第一个整数的索引
- signals - 采样率为 500hz 的复杂信号
- docker - Docker 容器在手动运行容器时可由 localhost 访问,但在由 jenkinsfile 运行时无法访问
- c# - 如何从安卓应用打开推特?
- node.js - 使用 webpack 捆绑 Electron 主脚本
- intellij-idea - IntelliJ 是否具有添加(或删除)“this.”的功能。代码编辑器中显示的代码中适当点前面的前缀?
- python - Pytesseract 没有读取正确的单词
- c - 进程以退出代码 -1073741819 (0xC0000005) 结束 - C,CLion 但输出没有任何问题