我写了简单的类并定义了一个副本构造函数。
然后添加朋友等于比较运算符,并将int
与Int
template <class T>
class Int {
public:
T value;
Int(const T& value_) : value(value_) {
;
}
friend bool operator==(const Int<T>& f, const Int<T>& s) {
return f.value == s.value;
}
};
int main() {
int a;
Int<int> x(a);
x == a;
}
编译成功。
如果我将friend bool operator==(const Int<T>& f, const Int<T>& s);
变成非朋友模板。我收到编译器错误:
error: no match for 'operator==' (operand types are 'int' and 'Int<int>'
template <class T>
class Int {
public:
T value;
Int(const T& value_) : value(value_) {
;
}
};
template <class T>
bool operator==(const Int<T>& f, const Int<T>& s) {
return f.value == s.value;
}
int main() {
int a;
Int<int> x(a);
x == a;
}
这是否意味着朋友功能允许特定的转换?
5 == x
也可以。
答案 0 :(得分:1)
c ++朋友关键字是否意味着比私人访问更多?
取决于上下文,它可能具有更多含义,是的。例如,一个friend
内联定义的函数,没有其他声明,即使它是封闭名称空间的成员,也只能通过依赖于参数的查找来找到:
namespace foo {
struct bar {
friend void baz(bar const&) {}
};
}
int main() {
foo::bar bar;
// foo::baz(bar); // ill-formed, no member baz in foo
baz(bar); // Okay, it *can* be found by ADL
};
这与您的问题没有直接关系,但是这就是查找朋友operator==
的方式。那个朋友也不是一个模板。实例化Int<int>
时,这会将“ operator==
”的免费功能(同样不是模板)“注入”到名称空间Int
的成员中。当出于执行x == a
的目的(通过ADL)查询该运算符函数时,编译器将很乐意考虑将a
隐式转换为Int<int>
,因为我们可以进行隐式转换以匹配常规免费功能。
谈到转化...
我写了简单的类并定义了一个副本构造函数。
您没有。那是一个用户定义的构造函数,带有一个int const&
参数,而不是像复制构造函数那样的Int<int> const&
。您定义了一个转换构造函数(因为它不是显式的),这正是编译器可以将上面的a
转换为Int<int>
的方式。
如果我转身...
在第二个版本中,运算符是模板。 ADL仍在查找它。但是模板参数推导只考虑参数的 exact 类型。也就是说,operator==
的两个参数必须能够直接绑定到Int<T> const&
并绑定T
。 int
无法直接绑定到Int<int> const&
,需要进行转换。因此,它与模板进行模板参数推导所需的参数类型不匹配。因此,该模板无法实例化,因此不是候选模板。
这是否意味着朋友功能允许特定的转换?
不,这不是友谊。这是模板业务与非模板业务。您可以定义没有友情的operator==
,但是必须对Int
进行每个实例化:
template <class T>
class Int {
public:
T value;
Int(const T& value_) : value(value_) {
;
}
};
bool operator==(const Int<int>& f, const Int<int>& s) {
return f.value == s.value;
}
这也会使您的main
的格式正确。但是,正如您所注意到的,不必分别声明它们并不是很有用,因此许多代码库都将使用friend
版本来自动“注入”该自由函数。