2016-05-12 4 views
4

Я хочу написать операционный код матрицы C++, некоторые операции для некоторых функций одинаковы. Интересно, есть ли способ их слияния? Например:Как сгенерировать функцию 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; 
     } 
    } 
} 

Две части кода почти одинаковы. Как я могу избежать перезаписи в два раза? Есть ли что-то вроде шаблона, который может автоматически генерировать код?

+0

Вы можете использовать 1D массив для хранения элементов матриц (сводится к 1 петле вместо 2 вложенных циклов), а затем использовать лямбды. –

+2

Вы понимаете, что передаете 'm' по значению, не так ли? Это означает, что ваша функция сделает копию переданного вектора и не обновит его при возврате. – selbie

+0

@selbie жаль, что не признаю это. Но моя проблема остается. – maple

ответ

1

Вы можете создать func со вторым аргументом и затем добавить его к каждому члену матрицы.

+0

Но программа будет очень медленной. – maple

+2

@maple. Использование '' является большим ударом по производительности, чем параметр аргумента. Это, а не передача вектора по ссылке. – selbie

+0

@maple: Какой компилятор вы используете, и проверили ли вы в обоих случаях, что сложение/вычитание фактически выполняется? (т. е. распечатать оригинал и результирующую матрицу) – MikeMB

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

Не используйте макросы для вещей, которые можно выполнить с помощью шаблонов. –

10

Вы можете определить шаблон функции и положить основную логику итерации элементов в этой функции.

Параметр шаблона может быть функтором, который может использоваться для определения того, что происходит для каждого конкретного вызова.

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

Я реализовал версию с функтором, но она работает очень медленно. Скорость составляет почти 1/5 прямой версии. – maple

+1

@maple Это отдельный вопрос. Это не должно. Я думаю, вы делаете что-то неправильно, либо в коде, либо в измерениях, либо в обоих. – Drop

+0

@Drop Я думаю, что во время каждой итерации он будет вызывать функцию, поэтому скорость может быть медленной? Это правда? – maple

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>> не очень кэш дружественных, так как вы disparse строки из матрицы по всей памяти. Было бы лучше, если бы у вас был собственный класс матриц, который бы использовал один из std::vector и перегружал бы операторов индексов для доступа row/column major.

+0

Почему вы используете ссылки пересылки, если вы не используете 'std :: forward'? – MikeMB

+0

@MikeMB для функторов прокси-объектов, но где вы бы использовали 'std :: forward' в показанном коде? – 101010

+0

Я бы не использовал 'std :: forward' и не перенаправлял ссылку, а просто передавал по значению. Моя точка зрения заключается в том, что - поскольку вы не перемещаетесь или не переадресовываетесь с 'f' - я не вижу, что« F && f »получает вас по сравнению с, например, 'const F & f'. – MikeMB

-2

Отказ от ответственности: Я нарушаю некоторые инкапсуляции C++, предлагаемые вектором, чтобы показать более быстрое решение, предлагающее то, что вы хотите, потенциально. Некоторые пуристы, которые болтают на тегах C++ на SO, обязательно ударят меня, показывая вам код ах. Но я все равно покажу вам. Вы можете сами принять решение.

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

Спасибо за ваш ответ, но у меня много другой операции, кроме + и -. – maple

+0

Затем перейдите к решению Р. Саху и оптимизируйте его, как вам нужно. – selbie

+0

Я не против взлома абстракций, если это повышает производительность, заметно, но я хотел бы знать, почему вы думаете, что это может быть более эффективным. – MikeMB

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

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; 
} 
Смежные вопросы