运算符<<必须只接受一个参数
operator << must take exactly one argument
a.h
#include "logic.h"
...
class A
{
friend ostream& operator<<(ostream&, A&);
...
};
逻辑.cpp
#include "a.h"
...
ostream& logic::operator<<(ostream& os, A& a)
{
...
}
...
当我编译时,它说:
std::ostream& logic::operator<<(std::ostream&, A&)' 必须只接受一个参数。
问题出在哪里?
问题是你在类中定义它,这
a) 表示第二个参数是隐式的 (this
和
b) 它不会做你想要它做的事情,即扩展std::ostream
。
您必须将其定义为自由函数:
class A { /* ... */ };
std::ostream& operator<<(std::ostream&, const A& a);
不是成员函数,所以问题是你声明operator<<
是 A
的 friend :
friend ostream& operator<<(ostream&, A&);
然后尝试将其定义为类 logic
的成员函数
ostream& logic::operator<<(ostream& os, A& a)
^^^^^^^
您是否对logic
是类还是命名空间感到困惑?
此错误是因为您尝试定义一个成员operator<<
采用两个参数,这意味着它需要三个参数,包括隐式this
参数。运算符只能接受两个参数,这样当你写a << b
时,两个参数是a
和b
。
您希望将ostream& operator<<(ostream&, const A&)
定义为非成员函数,绝对不是logic
的成员,因为它与该类无关!
std::ostream& operator<<(std::ostream& os, const A& a)
{
return os << a.number;
}
我在模板化类中遇到了这个问题。这是我必须使用的更通用的解决方案:
template class <T>
class myClass
{
int myField;
// Helper function accessing my fields
void toString(std::ostream&) const;
// Friend means operator<< can use private variables
// It needs to be declared as a template, but T is taken
template <class U>
friend std::ostream& operator<<(std::ostream&, const myClass<U> &);
}
// Operator is a non-member and global, so it's not myClass<U>::operator<<()
// Because of how C++ implements templates the function must be
// fully declared in the header for the linker to resolve it :(
template <class U>
std::ostream& operator<<(std::ostream& os, const myClass<U> & obj)
{
obj.toString(os);
return os;
}
现在:* 我的 toString() 函数不能内联,如果它要隐藏在 cpp 中。*你卡在标题中的一些代码,我无法摆脱它。* 运算符将调用 toString() 方法,它不是内联的。
运算符<<的主体可以在 friend 子句中声明,也可以在类外声明。这两种选择都很丑陋。:(
也许我误解或遗漏了一些东西,但只是向前声明运算符模板不会在 gcc 中链接。
这也有效:
template class <T>
class myClass
{
int myField;
// Helper function accessing my fields
void toString(std::ostream&) const;
// For some reason this requires using T, and not U as above
friend std::ostream& operator<<(std::ostream&, const myClass<T> &)
{
obj.toString(os);
return os;
}
}
我认为您还可以避免在标头中强制声明的模板问题,如果您使用未模板化的父类来实现运算符<<,并使用虚拟 toString() 方法。
运算符重载包括成员函数重载和非成员函数重载,不能混合使用。 https://condor.depaul.edu/ntomuro/courses/262/notes/lecture3.html
operator<<
定义为成员函数,它将具有与使用非成员operator<<
不同的分解语法。 非成员operator<<
是二元运算符,其中成员operator<<
是一元运算符。
// Declarations
struct MyObj;
std::ostream& operator<<(std::ostream& os, const MyObj& myObj);
struct MyObj
{
// This is a member unary-operator, hence one argument
MyObj& operator<<(std::ostream& os) { os << *this; return *this; }
int value = 8;
};
// This is a non-member binary-operator, 2 arguments
std::ostream& operator<<(std::ostream& os, const MyObj& myObj)
{
return os << myObj.value;
}
所以。。。。你真的怎么称呼他们? 运算符在某些方面很奇怪,我将挑战您在脑海中编写operator<<(...)
语法以使事情有意义。
MyObj mo;
// Calling the unary operator
mo << std::cout;
// which decomposes to...
mo.operator<<(std::cout);
或者,您可以尝试调用非成员二进制运算符:
MyObj mo;
// Calling the binary operator
std::cout << mo;
// which decomposes to...
operator<<(std::cout, mo);
当你把这些运算符变成成员函数时,你没有义务让它们表现得直观,如果你愿意,你可以定义operator<<(int)
左移一些成员变量,明白人们可能会有点措手不及,无论你写多少评论。
几乎最后,有时操作员呼叫的两个分解都有效,您可能会在这里遇到麻烦,我们将推迟该对话。
最后,请注意编写一个看起来像二进制运算符的一元成员运算符可能有多奇怪(因为您可以将成员运算符设置为虚拟.....也试图不下放并沿着这条路跑下去......
struct MyObj
{
// Note that we now return the ostream
std::ostream& operator<<(std::ostream& os) { os << *this; return os; }
int value = 8;
};
这种语法现在会激怒许多编码人员。
MyObj mo;
mo << std::cout << "Words words words";
// this decomposes to...
mo.operator<<(std::cout) << "Words words words";
// ... or even further ...
operator<<(mo.operator<<(std::cout), "Words words words");
请注意,cout
是这里链中的第二个参数。奇怪吧?
关键点是operator<<
之前的logic::
,它被定义为友元函数。
logic::
仅在成员函数之前添加。我知道这类似于告诉编译器这个函数是一个成员函数并授予它相应的权限(例如访问私有函数)。
换句话说,正如 @asaelr 和 @Morteza 提到的,"在定义 friend 函数时,您不会使用类的名称来限定 friend 函数的名称"。
因此,我们应该在operator<<
之前删除logic::
。
- 如何反转整数参数包
- 使用C++库在Android项目中修改gradle中的cmake参数,用于插入指令的测试
- 如何使用默认参数等选择模板专业化
- 模板参数替换失败,并且未完成隐式转换
- 具有默认模板参数的多态类的模板推导失败
- lambda参数转换为constexpr技巧,然后获取带链接的数组
- 将数组作为参数传递给函数安全吗?作为第三方职能部门,可以探索他们想要的之外的其他元素
- 函数调用中参数的顺序重要吗
- 部分定义/别名模板模板参数
- 模板-模板参数推导:三个不同的编译器三种不同的行为
- 使用不带参数的函数访问结构元素
- 基于另一个成员参数将函数调用从类传递给它的一个成员
- 如何在OMNET++中指定与命令行参数组合的输出文件名
- 如何使用Luacneneneba API正确读取字符串和表参数
- 在派生函数中指定void*参数
- 视图中的参数推导失败:take_while
- 请解释这句话(cout<<1+int((a<b)^((b-a)&1) )<<endl
- 左角支架解释为操作员&lt;而不是模板参数
- 重载运算符<<:此运算符函数的参数太多
- 重载<<运算符错误C2804:二进制'运算符<<'参数太多