如何自动生成C ++函数?

时间:2016-05-12 05:52:21

标签: c++ templates generics code-generation

我想编写一个c ++矩阵操作代码,某些函数的某些操作是相同的。我想知道是否有一些方法可以合并它们?例如:

void add1(vector<vector<double> > &m){
    for(int i = 0; i < m.size(); ++i){
        for(int j = 0; j < m[i].size(); ++j){
            m[i][j] += 1.0;
        }
    }
}

void minus1(vector<vector<double> > &m){
    for(int i = 0; i < m.size(); ++i){
        for(int j = 0; j < m[i].size(); ++j){
            m[i][j] -= 1.0;
        }
    }
}

两段代码几乎相同。如何避免重写两次?是否有类似模板可以自动生成代码?

8 个答案:

答案 0 :(得分:10)

您可以定义一个函数模板,并将迭代的核心逻辑放在该函数中的元素上。

模板参数可以是functor,可用于定义每个特定调用的内容。

// Change m to be a reference so the modifications to the elements
// are visible in the calling function.

template <typename Functor>
void for_each_member(vector<vector<double> >& m, Functor functor)
{
   for(std::size_t i = 0; i < m.size(); ++i){
      for(std::size_t j = 0; j < m[i].size(); ++j){
         functor(m[i][j]);
      }
   }
}

void add1(vector<vector<double> >& m){
   for_each_member(m, [](double& item) { item += 1.0;});
}

void minus1(vector<vector<double> >& m){
   for_each_member(m, [](double& item) { item -= 1.0;});
}

答案 1 :(得分:3)

您可以通过以下方式进行概括:

template<typename T, typename F>
void for_each_element(std::vector<std::vector<T>> &m, F &&f) {
  std::for_each(m.begin(), m.end(), [f] (auto &&v) {
    std::transform(v.begin(), v.end(), v.begin(), f);
  });
}

Live Demo

但是请注意,将矩阵表示为std::vector<std::vector<T>>并不是非常缓存,因为您在整个内存中分析矩阵的行。如果你有一个自定义矩阵类在内部使用一个std::vector并且会重载row/column major访问的下标运算符会更好。

答案 2 :(得分:1)

您可以使用第二个参数创建一个func,然后将其添加到矩阵的每个成员。

答案 3 :(得分:0)

你可以这样定义

template <template <class> class pred>
void apply(vector<vector<double>> & m) {
    for (auto & i : m)
        for (auto & j : i)
            j = pred<double>()(j, 1.0);
}

如需添加,请致电

apply<std::plus>(m);

类似地,对于减法

apply<std::minus>(m);

您还可以使用<functional>

中的其他功能对象

查看有效的DEMO

答案 4 :(得分:0)

您也可以为矩阵编写迭代器。这不完整但会给你一个想法:

#include <vector>
#include <algorithm>

template< class _T >
class Matrix
{
public:
    std::vector< std::vector< _T > > m_matrix;
    void alloc( size_t rows, size_t cols )
    {
        m_matrix.resize( rows );
        std::for_each( m_matrix.begin(), m_matrix.end(), [cols](std::vector<_T> &t){t.resize(cols);});
    }
    class iterator
    {
    public:
        iterator( std::vector< std::vector< _T > > & v ):
            m_vbegin( v.begin() ),
            m_vi( v.begin() ),
            m_i( m_vi->begin() ),
            m_vend( v.end() )
        {}
        iterator& operator++()
        {
            if ( ++m_i == m_vi->end() )
            {
                if ( ++m_vi != m_vend )
                    m_i = m_vi->begin();
            }
            return (*this);
        }
        void gotobegin()
        {
            m_vi=m_vbegin;
            m_i=m_vi->begin();
        }
        void gotoend()
        {
            m_vi=m_vend;
        }
        _T & operator*()
        {
            return *m_i;
        }
        bool operator==(const iterator & rhs )
        {
            if ( m_vi==rhs.m_vi && (m_vi==m_vend || m_i==rhs.m_i) )
                return true;
            return false;
        }
        bool operator!=(const iterator & rhs )
        {
            return !( *this == rhs );
        }
    private:
        typename std::vector< std::vector< _T > >::iterator m_vi;
        const typename std::vector< std::vector< _T > >::iterator m_vbegin;
        const typename std::vector< std::vector< _T > >::iterator m_vend;
        typename std::vector< _T >::iterator m_i;
    };
    iterator begin(){ return iterator(m_matrix); }
    iterator end(){ iterator ret(m_matrix); ret.gotoend(); return ret;}
};
int main( void )
{
    Matrix<double> matrix;
    matrix.alloc( 4000, 4000 );
    std::for_each( matrix.begin(), matrix.end(), []( double &t){ t=1.0;} );
    std::for_each( matrix.begin(), matrix.end(), []( double &t){ t+=1.0;} );
    return 0;
}

答案 5 :(得分:-1)

除了其他答案。您还可以使用std::function(请参阅http://en.cppreference.com/w/cpp/utility/functional/function)。在这里,您必须定义返回类型以及参数类型。使用它,您可以传递任何可调用的内容。

以下是一个例子:

#include <iostream>
#include <functional>
#include <vector>

using matrix = std::vector<std::vector<double>>;

void for_each_member(matrix& m, std::function<void(double&)> functor)
{
  for (auto &vec : m)
    for (auto &element : vec)
      functor(element);
}

static void sub(double &ele)
{
  --ele;
}

int main()
{
  matrix m = { {1,2}, {3,4} };

  for_each_member(m, [](auto &ele) { ++ele; });
  for_each_member(m, [](auto &ele) {std::cout << ele << " "; });

  std::cout << "\n";

  for_each_member(m, sub);
  for_each_member(m, [](auto &ele) {std::cout << ele << " "; });
  std::cout << "\n";

  return 0;
}

答案 6 :(得分:-2)

这个怎么样:

       #include "stdafx.h"
       #include <vector>
       using namespace std;

       #define plus +=
       #define minus -=

       #define DO(x,m) for (size_t i = 0; i < m.size(); ++i) \
       for (size_t j = 0; j < m[i].size(); ++j) \
      m[i][j] x 1.0; \





   int _tmain(int argc, _TCHAR* argv[])
  {
     vector<vector<double>> rows;
     vector<double> col1(2, 3);
     vector<double> col2(2, 3);

     rows.push_back(col1);
     rows.push_back(col2);

     DO(plus,rows);

     return 0;
 }

答案 7 :(得分:-2)

免责声明:我打破了vector提供的一些C ++封装,以显示提供所需内容的潜在更快的解决方案。在SO上使用C ++标签的一些纯粹主义者肯定会因为向你展示一些 ahem C代码而敲门。但无论如何我还是要告诉你。你可以自己做出决定。

inline void add_to_every_element(vector<double>* rows, size_t m_size, double d)
{
    for (size_t i = 0; i < m_size; i++)
    {
        size_t row_size = rows[i].size();
        double* row = rows[i].data();
        for (size_t j = 0; j < row_size; j++)
        {
            row[j] += d;
        }
    }
}

void add1(vector<vector<double> > &m)
{
    add_to_every_element(m.data(), m.size(), 1.0);
}

void minus1(vector<vector<double>>& m)
{
    add_to_every_element(m.data(), m.size(), -1.0);
}