Reputation: 1892
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
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
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
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
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
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);
});
}
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
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
Reputation: 45
You can create a func with the second argument and then add it to each member of matrix.
Upvotes: 1