Я создал матричный класс на C++.
namespace LinAlg {
template <typename T> class Matrix {
public:
Matrix();
Matrix(const uint64_t &rows, const uint64_t &cols);
template <typename P> operator P() const;
private:
uint64_t rows_, cols_;
std::vector<std::vector<T>> arr_;
};
template <typename T> template <typename P> Matrix<T>::operator P() const {
if constexpr (std::is_same_v<P, Matrix<int>> ||
std::is_same_v<P, Matrix<double>> ||
std::is_same_v<P, Matrix<float>>) {
Matrix<P> m(this->rows_, this->cols_);
for (uint64_t i = 0; i < this->rows_; i++) {
for (uint64_t j = 0; j < this->cols_; j++) {
m.arr_[i][j] = static_cast<P>(this->arr_[i][j]);
}
}
return m;
}
throw std::invalid_argument("Not a valid type conversions\n");
}
} // namespace LinAlg
Я реализовал преобразование типов Matrix<T>
в Matrix<P>
. Когда я попытался преобразовать Matrix<int>
в Matrix<float>
в своем test.cpp, используя следующий код:
LinAlg::Matrix<int> M(3, 3);
std::cin >> M;
LinAlg::Matrix<float> M1(3, 3);
std::cin >> M1;
std::cout << static_cast<LinAlg::Matrix<float>>(M) + M1 << "\n";
Я получаю ошибки типа arr_
— это private
в контексте:
m.arr_[i][j] = static_cast<P>(this->arr_[i][j]);
У вашего Matrix
, вероятно, есть какие-то общедоступные методы для получения/установки значений в матрице. Вы можете использовать его для решения проблемы, упомянутой в комментарии выше.
@wohlstad Я мог бы реализовать метод установки, но тогда какой смысл объявлять членов частными, если пользователь может манипулировать ими с помощью установки?
Инкапсуляция частных членов не противоречит использованию сеттеров. Но в любом случае, как вы предполагали, что пользователи класса будут устанавливать данные? (Кстати, вы также не публиковали никаких геттеров, поэтому тот же вопрос актуален для любого доступа).
Другая проблема: в m.arr_[i][j] = static_cast<P>(this->arr_[i][j]);
- поскольку P
- это вся матрица (а не тип элемента) - static_cast<P>
попытка применить ее к элементу неверна.
... и у вас похожая проблема с Matrix<P> m(...);
.
@VedantYadav опубликовал полный ответ на все проблемы, упомянутые выше.
Ваша главная проблема в том, что Matrix<T1>
и Matrix<T2>
(для типов T1
,T2
) — разные и не связанные между собой типы.
Поэтому Matrix<T1>
не может получить доступ к частному члену в Matrix<T2>
, и это является источником ошибки, которую вы получаете о том, что arr_
является частным в этой строке:
m.arr_[i][j] = static_cast<P>(this->arr_[i][j]);
Преодолеть эту проблему можно двумя способами:
Добавьте общедоступные методы доступа (сеттеры, геттеры) в Matrix
и используйте их в реализации operator P()
вместо доступа к частному arr_
.
Мне это кажется лучшим решением, потому что пользователям класса, вероятно, в любом случае потребуются методы доступа для доступа к данным.
Если у вас есть веские причины избегать добавления аксессоров, и поскольку вы, похоже, поддерживаете только Matrix<int>
,Matrix<double>
, Matrix<float>
(на основании вашего if constexpt
), то вы можете подружиться с этими 3 классами:
friend Matrix<int>;
friend Matrix<double>;
friend Matrix<float>;
Это позволит вам получить доступ к приватному arr_
.
Другая проблема в вашем коде заключается в том, что P
— это тип целого Matrix<X>
(для некоторого типа X
), а не тип элемента в Matrix
.
Поэтому эти две строки неверны:
Matrix<P> m(this->rows_, this->cols_);
И:
m.arr_[i][j] = static_cast<P>(this->arr_[i][j]);
Потому что они оба предполагают, что P
— это тип элементов в Matrix
.
Чтобы решить эту проблему, вы можете добавить псевдоним типа в Matrix
(может быть полезно сделать его общедоступным):
template <typename T> class Matrix {
public:
using element_type = T;
// ...
};
Затем используйте его в двух строках выше:
Matrix<P::element_type> m(...);
И:
... = static_cast<P::element_type>(...);
Примечание. Возможно, вам придется использовать typename P::element_type
вместо P::element_type
(если ваша версия C++ более ранняя, чем C++20).
Matrix<A>
иMatrix<B>
— разные и неродственные типы. ЧастноеMatrix<A>::arr_
не будет доступно вMatrix<B>
. Вы могли бы сделать их друзьями.