Некоторые сведения о том, что я пытаюсь сделать: Я пытаюсь реализовать библиотеку, занимающуюся квантовой механикой. Поскольку квантовая механика - это просто линейная алгебра, я использую библиотеку линейных алгебр армадилло под ней. Армадилло использует ленивую оценку, чтобы сделать некоторые умные трюки с матрицами, что дает довольно хорошую абстракцию от того, что на самом деле происходит, и близко приближается к коду matlab.
Я хочу сделать что-то подобное, но я также хочу использовать auto
, что невозможно с armadillo (или собственным).
Я немного оглядывался, и этот ответ содержит то, что я считаю типичным способом реализации этого: qaru.site/info/113202/...
Проблема с этим подходом заключается в том, что когда вы пишете
auto C = A+B;
вы получаете C
, который является matrix_add
, а не matrix
. Даже если matrix_add
ведет себя так же, как и matrix
, тот факт, что matrix_add
содержит ссылки на A
и B
, неудобно переносить. Например.
auto A = matrix(2,2,{0,1,0,1});
auto B = matrix(2,2,{1,0,1,0});
auto C = A+B;
C.printmatrix(); // 1,1 ; 1,1
но
auto A = matrix(2,2,{0,1,0,1});
auto B = matrix(2,2,{1,0,1,0});
auto C = A+B;
A(0,0) = 1;
C.printmatrix(); // 2,1 ; 1,1
что противоречит интуиции. Поскольку математически интуитивное поведение - это то, чего я хочу достичь, это проблема.
Еще хуже то, что я делаю
auto sumMatrices(const matrix& A, const matrix& B)
{
return A+B;
}
который возвращает matrix_add
со ссылками на локальную память.
Мне бы очень хотелось иметь хорошее, перегруженное поведение, но также иметь возможность использовать auto
. Моя идея состояла в том, чтобы создать оболочку, которая может содержать ссылку или экземпляр:
template<class T>
class maybe_reference
{
public:
maybe_reference(const T& t):
ptr_(std::make_unique<T>(t)),
t_(*ptr_)
{}
maybe_reference(std::reference_wrapper<const T> t):
t_(t.get())
{}
const T& get(){return t_;}
private:
unique_ptr<T> ptr_;
const T& t_;
}
Это может быть не реализовано точно таким образом, но общая идея состоит в том, чтобы иметь два конструктора, которые можно четко отличить, чтобы гарантировать, что get()
возвращает либо объект, на который ссылается, либо тот, который находится в unique_ptr
.
Изменено matrix_add
:
class matrix_add {
public:
friend matrix_add operator+(const matrix& A, const matrix& B);
matrix_add(matrix_add&& other): A_(other.A_.get()), B_(other.B_.get()){}
private:
matrix_add(const matrix& A, const matrix& B): A_(std::ref(A)), B_(std::ref(B)){}
maybe_reference<matrix> A_;
maybe_reference<matrix> B_;
};
Я забыл все части, которые делают matrix_add
, как a matrix
. Идея состоит в том, чтобы объект ссылался на внешние объекты A & B, если он был сконструирован с помощью A + B, но когда он сконструирован для перемещения, он будет иметь копии.
Мой вопрос в основном: работает ли это?
Я думал, что конструктор move может быть удален в некоторых или во всех случаях, что может быть разрушительным.
Кроме того, есть ли альтернатива для достижения того же? Я искал, но кажется, что для линейной алгебры, по крайней мере, она либо ленивая, либо авто.
EDIT: благодаря тому, что нам напомнили о термине "шаблоны выражений", мой поиск в google был намного более плодотворным. Я нашел этот reddit-post: https://www.reddit.com/r/cpp/comments/4puabu/news_about_operator_auto/
и справочные документы, которые позволяют специфицировать "отливки" на авто. Это будет особенностью, которая действительно сделает всю эту работу.