C++ 内部定义类上的运算符 模板 甲级{ 结构B{ Tα,b; } B&O+(B&x、B&y){ 返回B(x.a+y.a,x.B+y.B); } int funcA(B&x,B&y){ 返回(x+y); } };
正如您可能猜到的,在编译过程中,我得到“运算符+必须接受零或一个参数”。 正确的。因为在运算符+中,“this”作为第一个参数传递。 因此,解决方案是将操作符定位在a类定义之外。 但是,函数funcA使用运算符+。所以它必须在A之前定义。但是操作符+本身使用A中定义的类B,它本身是一个模板,B是依赖类C++ 内部定义类上的运算符 模板 甲级{ 结构B{ Tα,b; } B&O+(B&x、B&y){ 返回B(x.a+y.a,x.B+y.B); } int funcA(B&x,B&y){ 返回(x+y); } };,c++,C++,正如您可能猜到的,在编译过程中,我得到“运算符+必须接受零或一个参数”。 正确的。因为在运算符+中,“this”作为第一个参数传递。 因此,解决方案是将操作符定位在a类定义之外。 但是,函数funcA使用运算符+。所以它必须在A之前定义。但是操作符+本身使用A中定义的类B,它本身是一个模板,B是依赖类 解决方案是什么?有一种方法可以在类的主体中定义自由函数: template <class T> class A { struct B { T a,b;
解决方案是什么?有一种方法可以在类的主体中定义自由函数:
template <class T>
class A {
struct B {
T a,b;
}
B& operator+ (B & x, B & y) {
return B(x.a + y.a, x.b + y.b);
}
int funcA (B & x, B & y){
return (x + y).a;
}
};
在我看来,这是处理这种情况的最简单方法。除了@SteveJessop的答案(这是最好的答案)之外,如果操作员要成为成员,它必须是
B
的成员,而不是a
:
struct B {
T a,b;
// the change from B& to B is nothing to do with defining
// the function here, it's to avoid returning a dangling reference.
friend B operator+ (B & x, B & y) {
return B(x.a + y.a, x.b + y.b);
}
};
模板
甲级{
公众:
结构B{
Tα,b;
B(常数T&x,常数T&y):a(x),B(y){}
B运算符+(常数B&rhs)常数{返回B(a+rhs.a,B+rhs.B);}
};
T funcA(B&x、B&y){
返回(x+y);
}
};
您可以向前声明操作符+
在A
之外,但是funcA
必须显式调用它。在这种情况下,您可能不希望在A
之外定义operator+
,但因为您已经要求
因此,解决方案是将运算符定位在a类定义之外。。。怎么做
这个答案说明了这是怎么回事
像molbdnilo一样,我也同意Steve Jessop的答案是最好的,也是你应该采用的解决这个问题的答案
template <typename T>
class A {
public:
struct B {
T a,b;
B(const T& x, const T& y) : a(x), b(y) {}
B operator+(const B& rhs) const { return B(a + rhs.a, b + rhs.b); }
};
T funcA (B & x, B & y){
return (x + y).a;
}
};
A类模板;
模板
typename A::B运算符+(typename A::B&x,typename A::B&y);
模板
甲级{
模板
友元类型名A::B运算符+(类型名A::B&x,
类型名称A::B&y);
结构B{
Tα,b;
B(tx,ty):a(x),B(y){}
};
静态T函数(B&x,B&y){
return::运算符+(x,y).a;
}
公众:
A(){
B a(0,1);
B(1,0);
funcA(a,b);
}
};
模板
typename A::B运算符+(typename A::B&x,
类型名称(A::B&y){
返回类型名A::B(x.A+y.A,x.B+y.B);
}
如果函数在类内部,而且类是stgruct,并且所有成员都是公共可访问的,那么为什么要选择Fried?第二件事,它是否阻止我们将“this”作为第一个参数传递给操作符+?它是一个自由函数,而不是成员函数。因此,不,您不能使用此
。我之所以将其作为一个所有成员都是公共的结构,是因为您在代码中对类B
执行了相同的操作;按值或引用引用引用参数会更礼貌。@Mike:是的,我只是复制了发问者对函数的定义来演示这项技术。@SteveJessop:如果在a
中B
的定义之后声明它是一个自由函数,它也会起作用。另外,+1来自我。@user315052:虽然正向声明是一般的答案,但在本例中,它不是,而是将运算符的声明向前移动(这在这里无法完成),funcA
的定义必须向下移动。向下表示在哪里?根据定义,有必要让funcA成为A+1的成员,因为我非常喜欢Steve Jessop的答案。@DavidRodríguez dribeas:我的意图是实现Steve Jessop答案的效果,但在上面声明了A
的操作符+
转发,并在下面实现A
。我不明白为什么内联的朋友
可以让funcA
使用(x+y)
,但必须显式调用“概述的”朋友
。@user315052:B
是嵌套类型(a::B
),因此不能在定义封闭类型a
之前进行前向声明。这反过来意味着operator+(A::B,A::B)
不能在A
的定义之前在名称空间级别声明,因此之前不能将其声明为非友元。现在,如果您将其设置为朋友
,那么您可以在B
内部提供定义,也可以在类定义之后提供定义(该定义不影响查找),并且两个选项都可以。但这不是一个向前的声明,而是一个朋友的声明。在这个设计中有一些东西是错误的。第一个问题是,您正在打开A
类型以访问该操作员+
,该操作员根本不需要访问A
。第二个问题是,您正在打开对operator+
的所有专业化的访问权限,这是错误的,并且容易被滥用。这一点以及它比更好的解决方案更复杂的事实使得这一点成为不可能。@DavidRodríguez dribeas:我不反对,但我不同意“你不能向前宣布”的观点。正确的观点是“你可能不想”。但是,当有人确实想这样做的时候,答案是说明性的。我会澄清这个帖子。感谢并再次提醒您,您仍然不能将运算符+
转发声明为自由函数,而只能作为无模板函数。有些差异大多数人都不太理解,但这些是不同的概念。本例中最重要的区别之一是,根据Steve的回答,模板提供了唯一可供添加的实现,而在您提出的解决方案中,用户可以通过提供专门化来更改操作符+
的语义。还有其他区别,但这是最明显的区别。@DavidRodríguez dribeas:是的,他们可以专门化<
template <class T> class A;
template <class T>
typename A<T>::B operator + (typename A<T>::B &x, typename A<T>::B &y);
template <class T>
class A {
template <class U>
friend typename A<U>::B operator + (typename A<U>::B &x,
typename A<U>::B &y);
struct B {
T a,b;
B(T x, T y) : a(x), b(y) {}
};
static T funcA (B & x, B & y) {
return ::operator+<T>(x, y).a;
}
public:
A () {
B a(0, 1);
B b(1, 0);
funcA(a, b);
}
};
template <class T>
typename A<T>::B operator + (typename A<T>::B &x,
typename A<T>::B &y) {
return typename A<T>::B(x.a + y.a, x.b + y.b);
}