inf*_*ero 3 c++ templates operator-overloading
已经有很多关于这个主题的帖子了,但是提议的解决方案都没有帮助我编译和/或链接我的代码。
一般建议的解决方案是前向声明类,前向声明运算符/函数,将其声明为友元,然后实现它。
我尝试编译的代码是:
#include "matrix.hpp"
int main()
{
using namespace MLL;
Matrix<int, 4, 4> a({1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16});
a+a;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
#include <algorithm>
#include <array>
#include <type_traits>
#include <vector>
namespace MLL{
template<typename data_t, std::size_t n_rows, std::size_t n_cols, std::size_t MAX = 256>
class Matrix;
template<typename data_t, typename T, std::size_t n_rows, std::size_t n_cols, std::size_t MAX, std::size_t other_MAX>
Matrix<decltype(std::declval<data_t>() + std::declval<T>()), n_rows, n_cols, std::min(MAX, other_MAX)>
operator+(Matrix<data_t, n_rows, n_cols, MAX> const& lhs, Matrix<T, n_rows, n_cols, other_MAX> const& rhs);
template<typename data_t, std::size_t n_rows, std::size_t n_cols, std::size_t MAX>
class Matrix{
static constexpr bool IS_STATIC = n_rows * n_cols <= MAX;
using container_t = typename std::conditional<IS_STATIC, std::array<data_t, n_rows * n_cols>, std::vector<data_t>>::type;
container_t m_data_list;
public:
Matrix(){
if constexpr( !IS_STATIC ){
m_data_list.resize(n_rows * n_cols);
}
}
explicit Matrix(data_t default_value){
if constexpr( IS_STATIC ){
m_data_list.fill(default_value);
}else{
m_data_list.resize(n_rows * n_cols, default_value);
}
}
explicit Matrix(std::initializer_list<data_t>&& value_list){
std::copy(value_list.begin(), value_list.end(), m_data_list.begin());
}
Matrix(Matrix const& other)
: m_data_list(other.m_data_list){
}
Matrix(Matrix&& other) noexcept
: m_data_list(std::move(other.m_data_list)){
}
Matrix& operator=(Matrix const& other){
m_data_list = other.m_data_list;
return *this;
}
Matrix& operator=(Matrix&& other) noexcept{
m_data_list = std::move(other.m_data_list);
return *this;
}
template<typename T, std::size_t other_MAX>
friend Matrix<decltype(std::declval<data_t>() + std::declval<T>()), n_rows, n_cols, std::min(MAX, other_MAX)>
operator+(Matrix<data_t, n_rows, n_cols, MAX> const& lhs, Matrix<T, n_rows, n_cols, other_MAX> const& rhs);
};
template<typename data_t, typename T, std::size_t n_rows, std::size_t n_cols, std::size_t MAX, std::size_t other_MAX>
Matrix<decltype(std::declval<data_t>() + std::declval<T>()), n_rows, n_cols, std::min(MAX, other_MAX)>
operator+(Matrix<data_t, n_rows, n_cols, MAX> const& lhs, Matrix<T, n_rows, n_cols, other_MAX> const& rhs){
const std::size_t n = n_rows * n_cols;
for( std::size_t i = 0; i < n; ++i ){
lhs.m_data_list[i] += rhs.m_data_list[i];
}
return lhs;
}
}
Run Code Online (Sandbox Code Playgroud)
这里链接器抱怨该函数没有实现。
undefined reference to `MLL::Matrix<decltype (((std::declval<int>)())+((declval<int>)())), 4ull, 4ull, (std::min<unsigned long long>)(256ull, 256ull)> MLL::operator+<int, 256ull>(MLL::Matrix<int, 4ull, 4ull, 256ull> const&, MLL::Matrix<int, 4ull, 4ull, 256ull> const&)'
Run Code Online (Sandbox Code Playgroud)
#include <algorithm>
#include <array>
#include <type_traits>
#include <vector>
namespace MLL{
template<typename data_t, std::size_t n_rows, std::size_t n_cols, std::size_t MAX = 256>
class Matrix;
template<typename data_t, typename T, std::size_t n_rows, std::size_t n_cols, std::size_t MAX, std::size_t other_MAX>
Matrix<decltype(std::declval<data_t>() + std::declval<T>()), n_rows, n_cols, std::min(MAX, other_MAX)>
operator+(Matrix<data_t, n_rows, n_cols, MAX> const& lhs, Matrix<T, n_rows, n_cols, other_MAX> const& rhs);
template<typename data_t, std::size_t n_rows, std::size_t n_cols, std::size_t MAX>
class Matrix{
static constexpr bool IS_STATIC = n_rows * n_cols <= MAX;
using container_t = typename std::conditional<IS_STATIC, std::array<data_t, n_rows * n_cols>, std::vector<data_t>>::type;
container_t m_data_list;
public:
Matrix(){
if constexpr( !IS_STATIC ){
m_data_list.resize(n_rows * n_cols);
}
}
explicit Matrix(data_t default_value){
if constexpr( IS_STATIC ){
m_data_list.fill(default_value);
}else{
m_data_list.resize(n_rows * n_cols, default_value);
}
}
explicit Matrix(std::initializer_list<data_t>&& value_list){
std::copy(value_list.begin(), value_list.end(), m_data_list.begin());
}
Matrix(Matrix const& other)
: m_data_list(other.m_data_list){
}
Matrix(Matrix&& other) noexcept
: m_data_list(std::move(other.m_data_list)){
}
Matrix& operator=(Matrix const& other){
m_data_list = other.m_data_list;
return *this;
}
Matrix& operator=(Matrix&& other) noexcept{
m_data_list = std::move(other.m_data_list);
return *this;
}
template<typename T, typename U, std::size_t m_rows, std::size_t m_cols, std::size_t this_MAX, std::size_t other_MAX>
friend Matrix<decltype(std::declval<T>() + std::declval<U>()), m_rows, m_cols, std::min(this_MAX, other_MAX)>
operator+(Matrix<T, m_rows, m_cols, this_MAX> const& lhs, Matrix<T, m_rows, m_cols, other_MAX> const& rhs);
};
template<typename data_t, typename T, std::size_t n_rows, std::size_t n_cols, std::size_t MAX, std::size_t other_MAX>
Matrix<decltype(std::declval<data_t>() + std::declval<T>()), n_rows, n_cols, std::min(MAX, other_MAX)>
operator+(Matrix<data_t, n_rows, n_cols, MAX> const& lhs, Matrix<T, n_rows, n_cols, other_MAX> const& rhs){
const std::size_t n = n_rows * n_cols;
for( std::size_t i = 0; i < n; ++i ){
lhs.m_data_list[i] += rhs.m_data_list[i];
}
return lhs;
}
}
Run Code Online (Sandbox Code Playgroud)
错误2
C:/Users/CLionProjects/MLL/include/matrix.hpp:68:17: error: 'MLL::Matrix<int, 4, 4>::container_t MLL::Matrix<int, 4, 4>::m_data_list' is private within this context
68 | lhs.m_data_list[i] += rhs.m_data_list[i];
| ~~~~^~~~~~~~~~~
C:/Users/CLionProjects/MLL/include/matrix.hpp:19:21: note: declared private here
19 | container_t m_data_list;
| ^~~~~~~~~~~
C:/Users/CLionProjects/MLL/include/matrix.hpp:68:39: error: 'MLL::Matrix<int, 4, 4>::container_t MLL::Matrix<int, 4, 4>::m_data_list' is private within this context
68 | lhs.m_data_list[i] += rhs.m_data_list[i];
| ~~~~^~~~~~~~~~~
C:/Users/CLionProjects/MLL/include/matrix.hpp:19:21: note: declared private here
19 | container_t m_data_list;
| ^~~~~~~~~~~h
C:/Users/CLionProjects/MLL/include/matrix.hpp:68:32: error: assignment of read-only location 'lhs.MLL::Matrix<int, 4, 4>::m_data_list.std::array<int, 16>::operator[](i)'
68 | lhs.m_data_list[i] += rhs.m_data_list[i];
| ~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~
ninja: build stopped: subcommand failed.
Run Code Online (Sandbox Code Playgroud)
我不想在朋友声明中定义它。
您能否解释一下我在这两种情况下做错了什么,以及如何解决它?
第一个片段的问题是函数模板的友元声明只有operator+两个参数,而实现的operator+模板有 6 个参数。也就是说,友元声明适用于与您实现的函数模板不同的函数模板。
另外请注意,您实际上不需要模板和Matrix重载的operator+.
在下面修改后的程序中,我删除了这些前向声明(但如果您愿意,您可以拥有它们),并且我使用注释突出显示了我所做的更改。如果您决定使用前向声明,请确保仅256在前向声明中而不是在定义中提供默认参数。
此外,为了更好的可读性,我在重载的每个模板参数之后添加了后缀 ,以便可以轻松地将其与封闭类模板的模板参数分开。OPoperator+
此外,由于lhs是 const 左值引用,我们无法lhs.m_data_list[i] += rhs.m_data_list[i]使用该引用进行赋值。因此,在下面的代码中,我注释掉了该语句,如我的评论所示。
namespace MLL{
// template<typename data_t, std::size_t n_rows, std::size_t n_cols, std::size_t MAX=256>
// class Matrix; //this forward declaration not needed but you can have this if you want and if you do then make sure that you only provide the default arg 256 in declaration and not in definition
//--------------------------------------------------------------------------------vvvvvvv---->added this default arg here instead of in forward declaration
template<typename data_t, std::size_t n_rows, std::size_t n_cols, std::size_t MAX=256>
class Matrix{
static constexpr bool IS_STATIC = n_rows * n_cols <= MAX;
using container_t = typename std::conditional<IS_STATIC, std::array<data_t, n_rows * n_cols>, std::vector<data_t>>::type;
container_t m_data_list;
public:
Matrix(){
if constexpr( !IS_STATIC ){
m_data_list.resize(n_rows * n_cols);
}
}
explicit Matrix(data_t default_value){
if constexpr( IS_STATIC ){
m_data_list.fill(default_value);
}else{
m_data_list.resize(n_rows * n_cols, default_value);
}
}
explicit Matrix(std::initializer_list<data_t>&& value_list){
std::copy(value_list.begin(), value_list.end(), m_data_list.begin());
}
Matrix(Matrix const& other)
: m_data_list(other.m_data_list){
}
Matrix(Matrix&& other) noexcept
: m_data_list(std::move(other.m_data_list)){
}
Matrix& operator=(Matrix const& other){
m_data_list = other.m_data_list;
return *this;
}
Matrix& operator=(Matrix&& other) noexcept{
m_data_list = std::move(other.m_data_list);
return *this;
}
//renamed all the arguments by prefexing them with OP for better readibility
template<typename data_tOP, typename TOP, std::size_t n_rowst, std::size_t n_colsOP, std::size_t MAXOP, std::size_t other_MAXOP>
friend Matrix<decltype(std::declval<data_tOP>() + std::declval<TOP>()), n_rowst, n_colsOP, std::min(MAXOP, other_MAXOP)>
operator+(Matrix<data_tOP, n_rowst, n_colsOP, MAXOP> const& lhs, Matrix<TOP, n_rowst, n_colsOP, other_MAXOP> const& rhs);
};
template<typename data_tOP, typename TOP, std::size_t n_rowst, std::size_t n_colsOP, std::size_t MAXOP, std::size_t other_MAXOP>
Matrix<decltype(std::declval<data_tOP>() + std::declval<TOP>()), n_rowst, n_colsOP, std::min(MAXOP, other_MAXOP)>
operator+(Matrix<data_tOP, n_rowst, n_colsOP, MAXOP> const& lhs, Matrix<TOP, n_rowst, n_colsOP, other_MAXOP> const& rhs){
const std::size_t n = n_rowst * n_colsOP;
for( std::size_t i = 0; i < n; ++i ){
// lhs.m_data_list[i] += rhs.m_data_list[i]; //can't assing using const lvalue reference
}
return lhs;
}
}
Run Code Online (Sandbox Code Playgroud)