在递归模板中通过引用传递模板化函数

时间:2017-09-05 19:52:09

标签: c++ c++11 templates recursion

在我的博士学位中,我经常使用各种维度和数据类型的矩阵。我第一次使用 C ++ 11 中的递归模板来操作我的非连续数组,所以这是我最后一次看到callocfree。在stackoverflow link1link2的帮助下,我实现了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());
}

如果你到目前为止,谢谢! 克里斯

1 个答案:

答案 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);
  }
}

我们已经完成了。