Передача по ссылке, если возможно, по значению в противном случае - PullRequest
0 голосов
/ 31 марта 2019

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

Matrix<T> m(A.tri_lo());

Преобразование, здесь tri_lo() возвращает новое значение, поэтому здесьмой код выдает ошибку:

error C2662: 'Matrix<long double> Matrix<long double>::tri_lo(bool)' : cannot convert a 'this' pointer from 'const Matrix<long double>' to 'Matrix<long double> &'

Я попытался перегрузить конструктор для передачи по значению, но не смог заставить его работать.Вот мои конструкторы:

Matrix() : data{ {T{}} } {}; // Implemented
Matrix(std::vector<std::vector<T>> _data) : data{ _data } {}; // Implemented
Matrix(unsigned int const lines, unsigned int const cols) { // Implemented
    for (unsigned int i = 0; i < lines; i++) { this->data.push_back(std::vector<T>(cols, T())); }
};
template<class T2> Matrix(Matrix<T2> const& other) : data{ other.data } {}; // Implemented
template<class T2> Matrix(Matrix<T2> const other) : data{ other.data } {} // Implemented

Где я иду не так?

РЕДАКТИРОВАТЬ: здесь контекст.

template<class T>
template<class T2>
auto Matrix<T>::operator-(Matrix<T2> const& other) {
    assert(this->lines() == other.lines());
    assert(this->cols() == other.cols());

    decltype(std::declval<T>() - std::declval<T2>()) T3;

    Matrix<T3> res(this->lines(), this->cols());

    for (unsigned int const i = 0; i < this->lines(); i++) {
        for (unsigned int const j = 0; j < this->cols(); i++) {
            res[i][j] -= other[i][j];
        }
    }

    return res;
}

Вот полная пастбина .Не стесняйтесь включать небольшой обзор кода, если это необходимо!

1 Ответ

1 голос
/ 31 марта 2019

Основные выпуски

Есть много проблем с вашим кодом, которые Visual Studio не уловил, но все же нарушает код.

Например, в строках 86 и 87 вашего файла для вставки:

decltype (std::declval<T>()*std::declval<T2>()) T3;
Matrix<T3> result = Matrix<T3>::gen_full(this->lines(), other.cols());

Вы объявляете переменную с именем T3, а затем пытаетесь использовать ее в качестве параметра шаблона для Matrix. Что должно быть:

// Declare T3 as a type
using T3 = decltype (std::declval<T>()*std::declval<T2>());
// Now we can use T3
Matrix<T3> result = Matrix<T3>::gen_full(this->lines(), other.cols());

Или здесь, в gen_full:

template<class T>
Matrix<T> Matrix<T>::gen_full(unsigned int lines, unsigned int cols, T value){
    for(unsigned int i = 0; i < lines; i++) {
        std::vector<T> line;
        for(unsigned int j = 0; j < cols; j++) {
            line.push_back(value);
        }
        this->data.push_back(line); // Error here
    }
};

Вы используете this, но gen_full является статической функцией, поэтому this недоступен.

Мы можем переписать его как:

template<class T>
Matrix<T> Matrix<T>::gen_full(unsigned int lines, unsigned int cols, T value){
    Matrix<T> m; 
    for(unsigned int i = 0; i < lines; i++) {
        std::vector<T> line;
        for(unsigned int j = 0; j < cols; j++) {
            line.push_back(value);
        }
        m.data.push_back(line); // Error here
    }
    return m; 
};

В строках 346 и 348 у вас та же проблема, что и в 86 и 87:

decltype(std::declval<T>() - std::declval<T2>()) T3;

Matrix<T3> res(this->lines(), this->cols());

Мы можем исправить это так же, как и там (с using T3 = decltype(...))

В строке 350 вы объявляете i как const, а затем увеличиваете его. Мы можем просто удалить const, и это работает.

Другие вопросы

Как только мы справились с основными проблемами, есть еще несколько других проблем, которые мы можем уловить, только пытаясь создать экземпляр класса.

Например, мы можем использовать фиктивную функцию, чтобы компилятор проверил это для нас:

void foo() {
    // Forces the compiler to instantiate Matrix<double>
    Matrix<double> A;
    Matrix<double> B(A.tri_lo()); 
}

Когда мы пытаемся это сделать, мы получаем несколько загадочных ошибок, например, здесь, в строке 260:

Matrix<T> res(this->lines(), this->cols());

Gcc выдает ошибку

<source>: In instantiation of 'Matrix<T> Matrix<T>::tri_lo(bool) const [with T = double]':
<source>:365:31:   required from here
<source>:262:15: error: passing 'const Matrix<double>' as 'this' argument discards qualifiers [-fpermissive]
  262 |     Matrix<T> res(this->lines(), this->cols());
      |               ^~~

Это означает, что вы пытаетесь использовать функции, которые не являются const (например, lines() и cols()) в контексте const (поскольку tri_lo является const)

Мы можем исправить это, пометив lines() и cols() как const:

// On line 32 and 33
unsigned int cols() const; // Implemented
unsigned int lines() const; // Implemented

И здесь также:

// Lines 71 to 75
template<class T>
unsigned int Matrix<T>::cols() const { return this->data.size(); };

template<class T>
unsigned int Matrix<T>::lines() const { return this->data[0].size(); };

В чем причина первоначальной проблемы?

Насколько я могу судить, исходная проблема возникла из-за того, что lines() и cols() не были отмечены как const.

Заключение

Было много ошибок, которые Visual Studio не уловил. Рекомендуется использовать отдельный компилятор, такой как gcc или clang, который будет ловить ошибки быстрее и быстрее. Вы можете использовать их онлайн на https://godbolt.org, или вы можете установить их локально.

Вот оригинальная версия вашего кода вместе с ошибками, отображаемыми gcc: https://godbolt.org/z/5eiRNw

А вот обновленная версия вашего кода с исправленными ошибками (включая описанную в вашем исходном посте): https://godbolt.org/z/vFlyvk

Вам все еще нужно добавить реализацию Matrix<T>::gen_uninitialized, и в строке 226 clang предупреждает вас, что std::vector<T> diag(); интерпретируется как прямое объявление функции с именем diag (удалите скобки), но все остальное выглядит хорошо!

...