GCC和MSVC对使用模板的矩阵乘法方法抛出了编译错误,而Clang成功编译了这个没有任何错误,我无法理解为什么。有人可以提出错误吗?
我认为实例化operator*(matrix, matrix)
时存在问题。
注意:(错误:重新定义函数模板,C2995:函数模板已定义)[声明和定义在一个.hpp中,有标题保护]
我在gcc 7.2.0及更高版本和MSVC 19.14.26428.1及更高版本上进行了测试。我也使用C ++ 17标准。
有问题的方法:
template <std::size_t Rows_lhs, std::size_t Columns_lhs,
std::size_t Rows_rhs, std::size_t Columns_rhs>
friend constexpr matrix<value_type, Rows_lhs, Columns_rhs> operator*(
const matrix<value_type, Rows_lhs, Columns_lhs>& lhs,
const matrix<value_type, Rows_rhs, Columns_rhs>& rhs)
{
static_assert(Columns_lhs == Rows_rhs, "Incorrect matrix for product!");
matrix<value_type, Rows_lhs, Columns_rhs> result{};
container<value_type, Rows_rhs> thatColumn{};
for (size_type j = 0; j < Columns_rhs; ++j)
{
for (size_type k = 0; k < Rows_rhs; ++k)
{
thatColumn.at(k) = rhs(k, j);
}
for (size_type i = 0; i < Rows_lhs; ++i)
{
const auto thisRow = lhs(i);
value_type summand{};
for (size_type k = 0; k < Rows_rhs; ++k)
{
summand += thisRow.at(k) * thatColumn.at(k);
}
result(i, j) = summand;
}
}
return result;
}
完整代码:
#include <iostream>
#include <string>
#include <cmath>
#include <iterator>
#include <algorithm>
#include <array>
#include <initializer_list>
namespace vv
{
template <class Type = double, std::size_t Rows = 1, std::size_t Columns = 1>
class matrix
{
public:
using value_type = Type;
using size_type = std::size_t;
template <class Type = value_type, std::size_t N = Rows>
using container = std::array<Type, N>;
using row_container = container<value_type, Columns>;
using row_container_reference = container<value_type, Columns>&;
using const_row_container_reference = const container<value_type, Columns>&;
using reference = value_type&;
using const_reference = const value_type&;
using std_matrix = matrix<value_type, Rows, Columns>;
static constexpr value_type EPS = static_cast<value_type>(1e-10);
static_assert(std::is_arithmetic_v<value_type>, "Matrix elements type has to be arithmetic!");
static_assert(Rows > 0 && Columns > 0, "Incorrect size parameters!");
constexpr matrix() = default;
constexpr matrix(const std::initializer_list<value_type> list)
: _data()
{
size_type row_counter = 0;
size_type col_counter = 0;
for (const auto elem : list)
{
_data.at(row_counter).at(col_counter) = elem;
++col_counter;
if (row_counter == Rows && col_counter == Columns)
{
break;
}
if (col_counter == Columns)
{
col_counter = 0;
++row_counter;
}
}
}
std::string get_dimension() const noexcept
{
return std::to_string(Rows) + std::string("x")
+ std::to_string(Columns);
}
constexpr const_reference operator()(const size_type i, const size_type j) const
{
return _data.at(i).at(j);
}
constexpr reference operator()(const size_type i, const size_type j)
{
return _data.at(i).at(j);
}
constexpr const_row_container_reference& operator()(const size_type i) const
{
return _data.at(i);
}
constexpr row_container_reference& operator()(const size_type i)
{
return _data.at(i);
}
constexpr std_matrix& operator*=(const value_type num) noexcept
{
for (auto& row : _data)
{
for (auto& elem : row)
{
elem *= num;
}
}
return *this;
}
friend constexpr std_matrix operator*(const std_matrix& mat, const value_type num) noexcept
{
std_matrix temp(mat);
return (temp *= num);
}
friend constexpr std_matrix operator*(const value_type num, const std_matrix& mat) noexcept
{
return (mat * num);
}
friend std::ostream& operator<<(std::ostream& os, const std_matrix& mat)
{
os << "[" << mat.get_dimension() << "]\n";
for (const auto& row : mat._data)
{
std::copy(std::begin(row), std::end(row),
std::ostream_iterator<value_type>(os, " "));
os << '\n';
}
return os;
}
// PROBLEMS HERE BEGIN
template <std::size_t Rows_lhs, std::size_t Columns_lhs,
std::size_t Rows_rhs, std::size_t Columns_rhs>
friend constexpr matrix<value_type, Rows_lhs, Columns_rhs> operator*(
const matrix<value_type, Rows_lhs, Columns_lhs>& lhs,
const matrix<value_type, Rows_rhs, Columns_rhs>& rhs)
{
static_assert(Columns_lhs == Rows_rhs, "Incorrect matrix for product!");
matrix<value_type, Rows_lhs, Columns_rhs> result{};
container<value_type, Rows_rhs> thatColumn{};
for (size_type j = 0; j < Columns_rhs; ++j)
{
for (size_type k = 0; k < Rows_rhs; ++k)
{
thatColumn.at(k) = rhs(k, j);
}
for (size_type i = 0; i < Rows_lhs; ++i)
{
const auto thisRow = lhs(i);
value_type summand{};
for (size_type k = 0; k < Rows_rhs; ++k)
{
summand += thisRow.at(k) * thatColumn.at(k);
}
result(i, j) = summand;
}
}
return result;
}
// END
private:
container<container<value_type, Columns>, Rows> _data;
};
} // namespace vv
int main()
{
constexpr vv::matrix<double, 2, 1> a{ 1.0, 2.0 };
constexpr vv::matrix<double, 1, 2> b{ 4.0, 3.0 };
constexpr auto c = a * b; // This code occurs error.
std::cout << c;
return 0;
}