Как интегрировать библиотеку, которая использует шаблоны выражений?
Я хотел бы использовать библиотеку Eigen-матрицы в качестве механизма линейной алгебры в своей программе. Eigen использует шаблоны выражений для реализации ленивой оценки и упрощения циклов и вычислений.
Например:
#include<Eigen/Core>
int main()
{
int size = 40;
// VectorXf is a vector of floats, with dynamic size.
Eigen::VectorXf u(size), v(size), w(size), z(size);
u = 2*v + w + 0.2*z;
}
Так как Eigen использует шаблоны выражений, код типа
u = 2*v + w + 0.2*z;
В приведенном выше примере сводятся к одному циклу длиной 10 (не 40, поплавки вносятся в регистр с помощью блоков 4) без создания временного. Насколько это круто?
Но если я интегрирую библиотеку следующим образом:
class UsingEigen
{
public:
UsingEigen(const Eigen::VectorXf& data):
data_(data)
{}
UsingEigen operator + (const UsingEigen& adee)const
{
return UsingEigen(data_ + adee.data_);
}
...
private:
Eigen::VectorXf data_;
}
Тогда выражения типа:
UsingEigen a, b, c, d;
a = b + c + d;
не может использовать способ Eigen. И это не последнее. Существует много других примеров, в которых шаблоны экспрессии используются в Eigen.
Легким решением было бы не определять операторы самостоятельно, сделать data_
общедоступным и просто писать выражения, например:
UsingEigen a, b, c, d;
a.data_ = b.data_ + c.data_ + d.data_;
Это разрушает инкапсуляцию, но сохраняет эффективность Eigen.
Другим способом может быть создание собственных операторов, но пусть они возвращают шаблоны выражений. Но так как я новичок в С++, я не знаю, правильно ли это сделать.
Прошу прощения, если вопрос носит слишком общий характер. Я новичок, и мне не о чем спросить. До сих пор я использовал std::vector<float>
всюду, но теперь мне также нужно использовать матрицы. Переход от std::vector<float>
к Eigen во всем моем проекте - большой шаг, и я боюсь ошибиться в самом начале игры. Любые советы приветствуются!
Ответы
Ответ 1
Почему выставлять data_
прерывание инкапсуляции? Инкапсуляция означает скрытие деталей реализации и только отображение интерфейса. Если ваш класс оболочки UsingEigen
не добавляет никакого поведения или состояния в собственную библиотеку Eigen
, интерфейс не изменяется. В этом случае вы должны полностью удалить эту оболочку и написать свою программу с помощью структур данных Eigen
.
Воздействие матрицы или вектора не нарушает инкапсуляцию: только просмотр реализации матрицы или вектора мог бы сделать это. Библиотека Eigen
предоставляет арифметические операторы, но не их реализацию.
В библиотеках шаблонов выражений наиболее распространенным способом расширения возможностей библиотеки является добавление поведения, а не добавление путем добавления состояния. А для добавления поведения вам не нужно писать классы-оболочки: вы также можете добавить функции, отличные от членов, которые реализованы в терминах функций-членов класса Eigen
. См. этот столбец "Как функции, отличные от членов, улучшают инкапсуляцию" Скотта Мейерса.
Что касается вашей обеспокоенности тем, что преобразование вашей текущей программы в версию, которая явно использует функциональность Eigen
: вы можете выполнять пошаговое изменение, каждый раз меняя небольшие части своей программы, следя за тем, чтобы ваш блок (у вас есть модульные тесты, не так ли?) не ломаются, когда вы идете вперед.
Ответ 2
По-моему, это скорее проблема объектно-ориентированного проектирования, чем проблема использования библиотеки.
Все, что вы читаете из книг, - это правильные рекомендации. то есть не выставлять переменные-члены и защищать верхние уровни от нюансов использования стороннего уровня.
То, что вы могли бы ожидать, - это правильные абстракции математических функций, которые могут быть реализованы с использованием этой библиотеки внутренне. т.е. вы можете выставить собственную библиотеку с функциями высокого уровня, кроме элементарных векторных и матричных операций. Таким образом, вы можете использовать особенности взаимодействия между библиотечными объектами и в то же время вам не нужно подвергать переменные-члены верхним уровням.
Например, вы можете абстрагировать мои API более высокого уровня, такие как вычисление расстояния от точки до плоскости, расстояние между двумя плоскостями, вычисление новых координат точки по другой системе координат с использованием матриц преобразования и т.д. Для реализации этих методов внутренне вы можете использовать объекты библиотеки. Вы можете ограничить доступ к каким-либо из классов библиотек, используемых в подписях API, чтобы избежать зависимости для верхних уровней в этой библиотеке.
Верхние уровни вашей программы должны быть выше уровня абстракции и не нужно беспокоиться об элементарных деталях реализации, например о том, как выполняется расчет расстояния от точки до плоскости и т.д. Кроме того, им даже не нужно знать если этот нижний уровень реализован с использованием этой библиотеки или что-то еще. Они просто будут использовать интерфейсы вашей библиотеки.
Ответ 3
Я не понимаю весь ваш вопрос, я постараюсь ответить вам на большинство из них.
В этом предложении:
UsingEigen operator + (const UsingEigen& adee)const
{
return UsingEigen(data_ + adee.data_);
}
У вас есть оператор перегрузки (извините, я не знаю, правильно ли это писать на английском языке), поэтому вы можете написать:
a = b + c + d;
вместо:
a.data_ = b.data_ + c.data_ + d.data_;
У вас не будет проблем, стоимость вашей программы будет одинаковой. Кроме того, у вас будет инкапсуляция и эффективность.
С другой стороны, если вы хотите определить своего оператора, вы можете сделать это, как это делает шаблон. Вы можете найти информацию о веб-поиске "оператор перегрузки", но похожа на это:
UsingEigen operator + (const UsingEigen& adee)const
{
return UsingEigen(data_ + adee.data_);
}
Вместо "+" вы можете поместить оператора и выполнить необходимые операции.
Если вы хотите создать матрицу, это просто. Вам нужно только создать массив массива или вектор вектора.
Я думаю, что-то вроде этого:
std::vector<vector<float>>
Я не уверен, но это легко, с другой стороны, вы можете использовать простую матрицу следующим образом:
float YourMatrix [размер] [размер];
Я надеюсь, что это может вам помочь. Я не понимаю весь ваш вопрос, если вам нужно что-то еще добавить меня в Google +, и я постараюсь вам помочь.
Извините за мой английский, надеюсь, вы все поймете, и это поможет вам.