在我的博士学位中,我经常使用各种维度和数据类型的矩阵。我第一次使用 C ++ 11 中的递归模板来操作我的非连续数组,所以这是我最后一次看到calloc
和free
。在stackoverflow link1和link2的帮助下,我实现了de&分配它们的初始目标。贪心我,我现在希望我的班级执行基本的单元操作e.i.另外,分裂。如果我使用enum
来确定执行了哪个操作,它可以正常工作,但我无法使用对执行操作的其他模板化函数的引用。
主要:
//Define the size of each dimension in a vector
int height = 3, width = 2;
std::vector<int> dimensions;
dimensions.push_back(height);
dimensions.push_back(width);
// Allocate a table of doubles 3x2
smatrix<double **> dbltbl(dimensions);
// Assign values in the cells
for (int r = 0; r < height; ++r)
for (int c = 0; c < width; ++c) {
dbltbl.uacc()[r][c] = (r * width + c) * 2.6;
}
// Create a table of ints from the table of doubles (rounded copy)
smatrix<int **> inttbl = dbltbl;
// Add cell-wise the table of ints to the table of doubles
dbltbl.cellwise_add(inttbl);
enum
方式
enum
:
enum clc_op { addition, subtration, multiplication, division };
操作功能:
template <typename S, typename T>
T add(S one, T two) {
return one + two;
}
递归模板解决方案:
template <typename S, typename T>
void cellwise_ops(S &src, T &dest, std::vector<int> dims, enum clc_op operation) {
switch (operation) {
case clc_op::addition:
dest = add(src, dest);
break;
//…
//...
}
}
template <typename S, typename T>
void cellwise_ops(S *src, T *dest, std::vector<int> dims, enum clc_op operation) {
if (dims.size() == 0)
return;
int toimp = dims.front();
dims.erase(dims.begin());
for (int i = 0; i < toimp; ++i) {
cellwise_ops(src[i], dest[i], dims, operation)
}
}
类方法(例如P = double **和U = int **):
template <typename P>
template <typename U>
void smatrix<P>::cellwise_add(smatrix<U> const &addend) {
U temp = addend.uacc();
cellwise_ops(temp, _full, _dim, clc_op::addition);
}
输出:
==========================================
Table of doubles:
0 2.6
5.2 7.8
10.4 13
==========================================
Table of ints from the table of doubles:
0 2
5 7
10 13
==========================================
Table of doubles+ints:
0 4.6
10.2 14.8
20.4 26
这个解决方案看起来并不优雅,让我相信这是错误的做法。所以,我尝试将操作作为函数的参考传递,并且我很难度过。
参考方式的功能:
添加(操作)功能保持不变。递归解决方案:
template <typename S, typename T>
void cellwise_ops(S &src, T &dest, std::vector<int> dims, T (*operation)(S, T)) {
dest = operation(src, dest);
}
template <typename S, typename T>
void cellwise_ops(S *src, T *dest, std::vector<int> dims, T (*operation)(S, T)) {
if (dims.size() == 0)
return;
int toimp = dims.front();
dims.erase(dims.begin());
for (int i = 0; i < toimp; ++i) {
cellwise_ops(src[i], dest[i], dims, operation);
}
}
班级方法:
template <typename P>
template <typename U>
void smatrix<P>::cellwise_add(smatrix<U> const &addend) {
U temp = addend.uacc();
cellwise_ops(temp, _full, _dim, add<U, P>);
}
错误:
./sm_example/smatrix.hpp:305:17: required from ‘void smatrix<P>::cellwise_add(const smatrix<U>&) [with U = int**; P = double**]’
./sm_example/sm_example.cpp:157:35: required from here
./sm_example/smatrix.hpp:159:19: error: invalid operands of types ‘double**’ and ‘double**’ to binary ‘operator+’
return (T)one + two;
我知道指针之间的添加是不允许的,虽然我知道编译器不会发生这种情况。我不知道如何解决它。如何在递归模板函数中通过引用传递操作的模板函数(add
)?我是否以错误的方式使用模板?
我暂时不想使用std::vector
,但欢迎提出意见。最糟糕的情况是,我的数据集在5个维度上达到100MBytes。
解决方案在C ++ 11 thx到@Yakk下面
操作功能:
struct add {
template <typename S, typename T>
S operator()(S &x, T &y) { return x + y; }
};
递归模板解决方案的最底层:
template <typename S, typename T, class Op>
void cellwise_ops(S &src, T &dest, std::vector<int> dims, Op &&operation) {
dest = operation(dest, src);
return;
}
班级方法:
template <typename P>
template <typename U>
void smatrix<P>::cellwise_add(smatrix<U> const &addend) {
cellwise_ops(addend.uacc(), _full, _dim, add());
}
如果你到目前为止,谢谢! 克里斯
答案 0 :(得分:2)
不要使用函数指针。
template <typename S, typename T>
T add(S one, T two) {
return (T)one + two;
}
const auto do_add=[](auto&&...args)->decltype(auto) {
return add( decltype(args)(args)... );
};
或
#define RETURNS(...) \
noexcept(noexcept(__VA_ARGS__)) \
-> decltype(__VA_ARGS__) \
{ return __VA_ARGS__; }
#define DO_FUNC(...) \
[](auto&&...args) \
RETURNS( __VA_ARGS__( decltype(args)(args)... ) )
const auto do_add=DO_FUNC(add);
在这两种情况下,我们都有一个代表添加内容的对象do_add
。如果您愿意,这也可以struct
手动编写,operator()
。
do_add
不是函数指针。
template <class S, class T, class Op>
void cellwise_ops(S &src, T &dest, std::vector<int> dims, Op&& operation)
{
dest = operation(src, dest);
}
template <class S, class T, class Op>
void cellwise_ops(S *src, T *dest, std::vector<int> dims, Op&& operation)
{
if (dims.size() == 0)
return false;
int toimp = dims.front();
dims.erase(dims.begin());
for (int i = 0; i < toimp; ++i) {
cellwise_ops(src[i], dest[i], dims, operation);
}
}
我们已经完成了。