c++ - 如何在运算符重载中将int类型的模板矩阵类静态转换为double类型?

标签 c++ c++11 templates operator-overloading class-template

编写一个运算符函数以将自定义模板矩阵类与标量相乘。

template <typename T>
class Matrix 
{
public:
    Matrix() //default constructor
    Matrix(size_t Row, size_t Col); //initialize with zeros of row,col 
    explicit Matrix(const vector<vector<T>> matElems); // create a matrix from vec<vec>>
    friend Matrix<ret_type> operator*(const Matrix<mat_type> matrix,
        const scalar_type scalar);

private:
    vector<vector<T>> elements;
    std::size_t nRows;
    std::size_t nCols;
};

template <typename mat_type, typename scalar_type,
    typename ret_type = decltype(mat_type()* scalar_type())>
    Matrix<ret_type> operator*(const Matrix<mat_type> matrix,
        const scalar_type scalar) 
{
    Matrix<mat_type> copy_matrix = matrix;

    Matrix<ret_type> result = static_cast<Matrix<ret_type>>(copy_matrix);

    for (vector<ret_type> v : result.elements)
    {
        std::transform(v.begin(), v.end(), v.begin(),
            std::bind1st(std::multiplies<ret_type>(), scalar));
    }
    return result;
}

错误:

no matching function for call to ‘Matrix<double>::Matrix(Matrix<int>&)’
  on the line   **Matrix<ret_type> result = static_cast<Matrix<ret_type>>(copy_matrix)**

这样做的原因是,如果 int 类型矩阵乘以 double 标量,则将其转换为 double。

最佳答案

您遇到类型不匹配问题!

Matrix是一个类模板,当您使用模板参数实例化时,它为您提供具体类型 T 。这意味着实例化的类具有两个不同的 T s 将是 Matrix 的两种不同类型.

这意味着 Matrix<ret_type>Matrix<mat_type> 不同,因此转换将不起作用,您已在这一行尝试过:

Matrix<ret_type> result = static_cast<Matrix<ret_type>>(copy_matrix);

这会产生编译器错误!

您需要迭代 Matrix<mat_type> 的每个元素并转换到ret_type并创建一个新的Matrix<ret_type>摆脱它。

话虽如此,

以下是更新后的代码。希望评论能带动代码!

#include <iostream>
#include <vector>
#include <utility>     // std::move
#include <type_traits> // std::common_type

template <typename T> class Matrix /* final */
{
private:
    std::vector<std::vector<T>> elements{};
    std::size_t nRows{};
    std::size_t nCols{};

public:
    Matrix() = default; // default constructor
    explicit Matrix(std::vector<std::vector<T>> matElems)
        : elements{ std::move(matElems) }
        , nRows{ elements.size() }
        , nCols{ elements.empty() ? 0u : elements[0].size() }
    {}

    template<typename mat_type, typename scalar_type>
    friend auto operator*(const Matrix<mat_type>& matrix, const scalar_type scalar)
        ->Matrix<typename std::common_type<mat_type, scalar_type>::type>;
        // or
        // -> Matrix<decltype(mat_type{} * scalar_type{})> ;

    // some useful member functions!
    void reserve(const std::size_t n) noexcept { elements.reserve(n); }
    std::size_t size() const noexcept { return elements.size(); }

    // to make the "Matrix" iteratable: Useful in range-based for loop/ standard algorithms.
    auto begin() noexcept ->decltype(elements.begin())  { return elements.begin(); }
    auto end() noexcept ->decltype(elements.end())  { return elements.end(); }

    auto begin() const noexcept ->decltype(elements.cbegin()) { return elements.cbegin(); }
    auto end() const noexcept ->decltype(elements.cend()) { return elements.cend(); }

    // operator<< overload for printing
    friend std::ostream& operator<<(std::ostream& out, const Matrix& obj) noexcept
    {
        for (const auto& raw: obj)
        {
            for (const T ele : raw) out << ele << ' ';
            out << '\n';
        }
        return out;
    }
};

// non-member operator* definition
template<typename mat_type, typename scalar_type>
auto operator*(const Matrix<mat_type>& matrix, const scalar_type scalar)
  -> Matrix<typename std::common_type<mat_type, scalar_type>::type>
  // or
  // -> Matrix<decltype(mat_type{} * scalar_type{}) >
{
    using ret_type = typename std::common_type<mat_type, scalar_type>::type;

    Matrix<ret_type> result; // default constructed matrix!
    // reserve some memory for "Matrix" for unwanted reallocations!
    result.reserve(matrix.size());  // calls the Matrix<T>::reserve()

    for (const std::vector<mat_type>& rawVec : matrix)
    {
        std::vector<ret_type> newRaw;
        // reserve the memory for raw vectors for unwanted reallocations!
        newRaw.reserve(rawVec.size());

        for (mat_type element : rawVec) newRaw.emplace_back(element * scalar);
        
        // add the updated raws to the "result"
        result.elements.emplace_back(newRaw);
    }
    return result;
}

int main()
{
    Matrix<int> matInt{ { {1, 2, 3}, {4, 5, 6}, {7, 8, 9} } };
    auto res = matInt * 0.1;
    std::cout << res; // 0.1 0.2 0.3 
                      // 0.4 0.5 0.6
                      // 0.7 0.8 0.9
    return 0;
}

这里是( a complete demo )


另外,请注意,您始终可以拥有一维 std::vector (如果 raw-size 和 col-size 是运行时)或 std::array (如果维度在编译时已知),并通过索引操作将它们视为二维数组。

关于c++ - 如何在运算符重载中将int类型的模板矩阵类静态转换为double类型?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/68879971/

相关文章:

c++ - 如何确定处理器是 32 位还是 64 位?双核处理器是 32 位还是 64 位?

C++ 等价于 Java 的匿名类

c++ - sizeof(function) 有意义吗?

c++ - 使用 C++ 正则表达式库中的 regex_search

c++ - 基于 boost::asio 的慢速 http 客户端 - (分块传输)

c++ - 代表模板类型的名称应该是单个字符吗?

c++ - 为什么有时需要将 C++ 模板函数定义放在头文件中?

c++ - 如何使用谷歌测试用例测试迭代器值?

c++ - std::async 与 std::promise

c++ - 如何告诉编译器我的 friend 函数是函数模板