分配矩阵的模板参数推导

template argument deduction for a allocating Matrix

我有这个 Matrix class 在堆上分配数据,还有一个助手 class M,它是一个矩阵,数据作为 C 样式数组,没有分配。模板参数推导自动适用于助手 class。但不是矩阵 class.

我可以用模板参数推导从中构造一个矩阵:

M m{{{1, 2}, {3, 4}}};
Matrix a{M{{{1, 2}, {3, 4}}}};

我正在寻找的是摆脱助手 class 所以以下工作:

Matrix a{{{1, 2}, {3, 4}}};

这是一个使用助手 class 的工作示例:https://godbolt.org/z/46vEqbvax

#include <cstddef>
#include <type_traits>
#include <cstring>
#include <initializer_list>
#include <utility>
#include <memory>
#include <cassert>
#include <algorithm>

template <typename T, std::size_t rows, std::size_t cols>
class M {
public:
    const T * operator[](std::size_t x) const {
        return data[x];
    }
    T * operator[](std::size_t x) {
        return data[x];
    }
    T data[rows][cols]{};
};

template <typename T, std::size_t rows, std::size_t cols>
class Matrix {
private:
    T *data{new T[rows * cols]};
public:
    Matrix() { }
    ~Matrix() {
        delete[] data;
        data = nullptr; // crash on use after free
    }
    Matrix(const Matrix &other) {
        *this = other;
    }
    Matrix(T &&other) : data(other.data) {
        other.data = nullptr;
    }
    Matrix & operator=(const Matrix &other) {
        if constexpr (std::is_aggregate_v<T>) {
            memcpy(data, other.data, sizeof(T) * rows * cols);
        } else {
            for (std::size_t i = 0; i < rows; ++i) {
                for (std::size_t j = 0; j < cols; ++j) {
                    (*this)[i][j] = other[i][j];
                }
            }
        }
        return *this;
    }
    Matrix operator=(Matrix &&other) {
        swap(data, other.data);
        return *this;
    }
    const T * operator[](std::size_t x) const {
        return &data[x * cols];
    }
    T * operator[](std::size_t x) {
        return &data[x * cols];
    }
    Matrix(const M<T, rows, cols>& other) {
        if constexpr (std::is_aggregate_v<T>) {
            memcpy(data, other.data, sizeof(T) * rows * cols);
        } else {
            for (std::size_t i = 0; i < rows; ++i) {
                for (std::size_t j = 0; j < cols; ++j) {
                    (*this)[i][j] = other[i][j];
                }
            }
        }
    }
    Matrix(M<T, rows, cols>&& other) {
        if constexpr (std::is_aggregate_v<T>) {
            memcpy(data, other.data, sizeof(T) * rows * cols);
        } else {
            for (std::size_t i = 0; i < rows; ++i) {
                for (std::size_t j = 0; j < cols; ++j) {
                    std::swap((*this)[i][j], other[i][j]);
                }
            }
        }
    }
};

//template <typename T, std::size_t rows, std::size_t cols>
//Matrix(M<T, rows, cols>) -> Matrix<T, rows, cols>;

#include <iostream>

int main() {
    Matrix a{M{{{1, 2}, {3, 4}}}};
    Matrix b{a};
    std::cout << b[0][0] << " " << b[0][1] << std::endl;
    std::cout << b[1][0] << " " << b[1][1] << std::endl;
}

您可以摆脱助手 class M 并通过将构造函数参数的类型更改为 (l- 和 r-value 引用)C-style 数组:

//Matrix(const M<T, rows, cols>& other) {
Matrix(const T (&other)[rows][cols]) {
    // ... same implementation ...
}

//Matrix(M<T, rows, cols>&& other) {
Matrix(T (&&other)[rows][cols]) {
    // ... same implementation ...
}

Demo