编写一个运算符函数以将自定义模板矩阵类与标量相乘。
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>
摆脱它。
话虽如此,
您不需要在那里进行类型转换。既然你想返回一个新的
Matrix<ret_type>
来自Matrix<int>
,您可以生成一个新的Matrix
具有传递的matrix
中所需的类型.std::bind1st
已在 c++11 中弃用 并已在 c++17 中删除。因此,将它们放入代码库中将会在未来的编译器更新中产生编译器错误。由于您可以访问c++11 ,使用lambda functions instead .最后但并非最不重要的一点是,请查看:Why is "using namespace std;" considered bad practice?
以下是更新后的代码。希望评论能带动代码!
#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/