我正在用c++编写一个用于矩阵运算的小型矩阵库。然而,我的编译器抱怨,以前它没有。这段代码被搁置了6个月,在此期间,我把我的电脑从debian etch升级到lenny (g++ (debian 4.3.2-1.1) 4.3.2
),但是我在Ubuntu系统上也遇到了同样的问题。
这是我的矩阵类的相关部分:
namespace Math
{
class Matrix
{
public:
[...]
friend std::ostream& operator<< (std::ostream& stream, const Matrix& matrix);
}
}
而“执行”:
using namespace Math;
std::ostream& Matrix::operator <<(std::ostream& stream, const Matrix& matrix) {
[...]
}
这是编译器给出的错误:
Matrix.cpp:459:错误:` std::ostream&
数学:矩阵::操作符< < (std::上ostream,
const Math::Matrix&)'必须取
只有一个参数
我对这个错误有点困惑,但在这6个月做了很多Java之后,我的c++已经有点生疏了。: -)
在c++ 14中,你可以使用下面的模板来打印任何具有T::print(std::ostream&)const;成员。
template<class T>
auto operator<<(std::ostream& os, T const & t) -> decltype(t.print(os), os)
{
t.print(os);
return os;
}
在c++ 20中可以使用概念。
template<typename T>
concept Printable = requires(std::ostream& os, T const & t) {
{ t.print(os) };
};
template<Printable T>
std::ostream& operator<<(std::ostream& os, const T& t) {
t.print(os);
return os;
}
假设我们讨论的是对std::ostream派生的所有类重载操作符<<来处理Matrix类(而不是对Matrix类重载<<),那么在头文件的Math命名空间之外声明重载函数更有意义。
只有在无法通过公共接口实现该功能时,才使用好友函数。
Matrix.h
namespace Math {
class Matrix {
//...
};
}
std::ostream& operator<<(std::ostream&, const Math::Matrix&);
注意,操作符重载是在名称空间之外声明的。
Matrix.cpp
using namespace Math;
using namespace std;
ostream& operator<< (ostream& os, const Matrix& obj) {
os << obj.getXYZ() << obj.getABC() << '\n';
return os;
}
另一方面,如果你的重载函数确实需要成为一个朋友,即需要访问私有和受保护的成员。
Math.h
namespace Math {
class Matrix {
public:
friend std::ostream& operator<<(std::ostream&, const Matrix&);
};
}
您需要将函数定义包含在一个名称空间块中,而不是仅仅使用名称空间Math;。
Matrix.cpp
using namespace Math;
using namespace std;
namespace Math {
ostream& operator<<(ostream& os, const Matrix& obj) {
os << obj.XYZ << obj.ABC << '\n';
return os;
}
}
只是告诉你另一种可能性:我喜欢使用朋友的定义:
namespace Math
{
class Matrix
{
public:
[...]
friend std::ostream& operator<< (std::ostream& stream, const Matrix& matrix) {
[...]
}
};
}
The function will be automatically targeted into the surrounding namespace Math (even though its definition appears within the scope of that class) but will not be visible unless you call operator<< with a Matrix object which will make argument dependent lookup find that operator definition. That can sometimes help with ambiguous calls, since it's invisible for argument types other than Matrix. When writing its definition, you can also refer directly to names defined in Matrix and to Matrix itself, without qualifying the name with some possibly long prefix and providing template parameters like Math::Matrix<TypeA, N>.
在c++ 14中,你可以使用下面的模板来打印任何具有T::print(std::ostream&)const;成员。
template<class T>
auto operator<<(std::ostream& os, T const & t) -> decltype(t.print(os), os)
{
t.print(os);
return os;
}
在c++ 20中可以使用概念。
template<typename T>
concept Printable = requires(std::ostream& os, T const & t) {
{ t.print(os) };
};
template<Printable T>
std::ostream& operator<<(std::ostream& os, const T& t) {
t.print(os);
return os;
}