gpt4 book ai didi

c++ - 重载二元运算符作为模板类 : Not recognized as friend or linker error 的友元

转载 作者:行者123 更新时间:2023-12-05 01:49:17 25 4
gpt4 key购买 nike

已经有很多关于这个主题的帖子,但是提出的解决方案都没有帮助我编译和/或链接我的代码。

一般建议的解决方案是前向声明类,前向声明运算符/函数,将其声明为友元,然后实现它。

我尝试编译的代码是:

#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;
}

变体 1

#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;
}
}

链接器在这里提示函数没有实现。

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&)'

变体 2

#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;
}
}

错误 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.

问题

我不想在 friend 声明中定义它。

能否请您解释一下我在这两种情况下做错了什么,以及我该如何解决?

最佳答案

第一个片段的问题是函数模板operator+的友元声明只有两个参数,而实现的operator+有6个模板参数。也就是说,友元声明针对的是与您实现的函数模板不同的函数模板

另外请注意,对于Matrix 模板和重载的operator+,您实际上不需要前向声明

在下面修改后的程序中,我删除了那些前向声明(但如果需要,您可以拥有它们)并且我使用注释突出显示了我所做的更改。如果您决定使用前向声明,请确保仅在前向声明中而不是在定义中提供默认参数 256

此外,为了更好的可读性,我在重载的 operator+ 的每个模板参数之后添加了 postfixed OP 以便它可以很容易地分开来自封闭类模板的模板参数。

此外,由于 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;
}
}

Working demo

关于c++ - 重载二元运算符作为模板类 : Not recognized as friend or linker error 的友元,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/74251179/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com