maple
maple

Reputation: 1892

How to generate C++ function automatically?

I want to write a c++ matrix operation code, some operation are the same for some function. I wonder whether there are some method to merge them? For example:

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;
        }
    }
}

The two pieces of code is almost the same. How can I avoid to rewrite it for two times? Are there something like template that can generate code automatically?

Upvotes: 4

Views: 1315

Answers (7)

mainactual
mainactual

Reputation: 1645

You could also write an iterator for your matrix. This is not complete but gives you an idea:

#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;
}

Upvotes: 0

Shreevardhan
Shreevardhan

Reputation: 12641

You could define it this way

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

For addition, call

apply<std::plus>(m);

similarly, for substraction

apply<std::minus>(m);

you can also use other function objects from <functional>

See a working DEMO.

Upvotes: 0

selbie
selbie

Reputation: 104559

Disclaimer: I'm breaking some C++ encapsulation offered by vector to show a potentially faster solution that offers what you want. Some purists that hang out on the C++ tags on SO are sure to knock me for showing you some ahem C code. But I'm going to show you anyway. You can make your own decision for yourself.

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

Upvotes: -2

Lukas
Lukas

Reputation: 1305

In addition to the other answers. You can also use a std::function (see http://en.cppreference.com/w/cpp/utility/functional/function). Here you have to define the return type as well as the parameter types. Using this you can pass anything that is callable.

Here is an example:

#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;
}

Upvotes: -1

Dimitrios Bouzas
Dimitrios Bouzas

Reputation: 42909

You could generalize in the following manner:

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

Mind however, that representing a matrix as a std::vector<std::vector<T>> is not very cache friendly, since you disparse the rows of the matrix all over the memory. It would be better if you had a custom matrix class that internally would use one std::vector and would overload the subscript operators for row/column major access.

Upvotes: 3

R Sahu
R Sahu

Reputation: 206637

You can define a function template and put the core logic of iterating over the elements in that function.

The template parameter can be functor which can be used to define what happens for each specific call.

// 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;});
}

Upvotes: 10

Denis
Denis

Reputation: 45

You can create a func with the second argument and then add it to each member of matrix.

Upvotes: 1

Related Questions