我编写了一个简短的程序来测试模板类的显式实例化,如下所示:
#include <iostream>
template <class T>
struct less_than_comparable {
friend bool operator>=(T const& a, T const& b) {
return !(a < b);
}
};
class Point {
friend bool operator<(Point const& a, Point const& b) {
return a.x_ < b.x_;
}
public:
Point(int x) : x_(x) {}
private:
int x_;
};
template struct less_than_comparable<Point>;
//Here I explicitly instantiate a template class expecting that
//less_han_comparable<Point> would export opeartor>=() for class Point to the global
//namespace, and then the p1 >= p2 statement will work as expected.
int main() {
using namespace std;
Point p1(1), p2(2);
cout << (p1 < p2) << endl;
cout << (p1 >= p2) << endl; //But I have a compiler error here saying that
//no match for ‘operator>=’ in ‘p1 >= p2’
}
我知道如果从less_than_comparable继承Point,代码将通过编译。 但我的问题是,如果我使用显式实例化,它为什么不起作用? 我使用在Ubuntu 10.04上运行的G ++ 4.4.5。 任何意见将不胜感激。感谢。
答案 0 :(得分:2)
问题是在类类型中定义的友元函数是而不是注入到封闭的命名空间中。
您所引用的原则称为“朋友名称注入”,但在当前C ++标准中已被“ADL”替换( Argument Dependent Lookup ,也称为 Koenig Lookup < / em>的)。 ADL检查与函数参数类型相关联的所有名称空间以匹配函数。
在您的情况下,当您在operator>=
(即p1 >= p2
)中致电operator>=(p1, p2);
时。 ADL在Point
的命名空间中查找匹配函数,但Point
没有此函数。
如果您从Point
继承less_than_comparable
,operator>=
将成为Point
命名空间的一部分,ADL可以在此处找到它。
您可以检查是否没有注明朋友姓名here。
答案 1 :(得分:1)
代码不起作用,因为Point
不是您定义operator >=
的模板类。
如果要编译此代码,请在Point类中定义operator >=
。请注意,p1
和p2
与less_than_comparable
无关。
作为旁注,为什么您在less_than_comparable
的名称中为“大于等于”运算符定义了运算符?
答案 2 :(得分:1)
显式实例化只是强制编译器在该转换单元中编译特定模板的一种方法 - 它对查找名称没有影响。
要获得您想要的内容,例如:
class Point : public less_than_comparable<Point> {
答案 3 :(得分:0)
你的运算符&gt; =是一个完全不同类型的成员函数,就编译器而言,它与Point无关。我想你想做的是:
template< T >
bool operator >= ( T const& a, T const& b ) {... }
忘记了课程,只是让它成为一个全局函数。而且您不需要显式模板实例化。事实上,我唯一一次看到它使用的是你在一个库中声明的模板类,并在另一个项目中使用,你显然没有在这里做。