假设我有一个小类模板,如下所示
template<typename T> class SillyClass {
public:
SillyClass(const T val);
SillyClass(const SillyClass& other);
private:
T data;
};
现在我添加以下 definitions 声明:
template<typename T> class SillyClass {
public:
SillyClass(const T val);
SillyClass(const SillyClass& other);
SillyClass<T> operator+ (const SillyClass& other);
SillyClass<T> operator+ (const T& val);
private:
T data;
};
现在(在我写完适当的定义之后)我可以做像
这样的事情SillyClass<int> a(1);
SillyClass<int> b(a);
SillyClass<int> c = a + b;
SillyClass<int> d = a + 3;
到目前为止,这么好。但是,能够写出像
这样的东西SillyClass<int> e = 3 + a;
我发现必须将以下声明添加到我的班级
template<typename T2> friend SillyClass<T2> operator+
(const T2& val, const SillyClass<T2>& other);
所以它现在读取
template<typename T> class SillyClass {
public:
SillyClass(const T val);
SillyClass(const SillyClass& other);
SillyClass<T> operator+ (const SillyClass& other);
SillyClass<T> operator+ (const T& val);
template<typename TT> SillyClass<TT> friend operator+
(const TT& val, const SillyClass<TT>& other);
private:
T data;
};
我没有在书中找到这个,我想帮助了解最后一个声明中发生了什么。例如,我的班级在这里结识了什么?为什么要附加模板声明?在导致相同结果的不同声明(能够执行3 + a,比方说)方面,我有哪些替代方案?
感谢。
答案 0 :(得分:1)
您可以定义您班级中的friend
运算符,而不是仅在课堂上声明您的运算符:
SillyClass<T> friend operator+(const T& val, const SillyClass<T>& other)
{
// define it here
}
这样,对于每个类的实例,都会生成相应的friend
。整个过程基于名为朋友名称注入的东西。
现在回到你的问题。如果您只是使用课堂内声明
friend operator+(const T& val, const SillyClass<T>& other);
然后在课堂外定义
template<typename T>
friend operator+(const T& val, const SillyClass<T>& other)
您将收到链接器错误。为什么?因为在实例化类时假设T=int
。然后你班上的宣言将读为
friend operator+(const int& val, const SillyClass<int>& other);
,只要您在operator+
和SillyClass<int>
上调用int
,就会比上面的模板定义更好地匹配。因此链接器将无法找到所需int
实例化的定义,因此会出现链接器错误。另一方面,我在答案开始时提出的解决方案保证 每个类型的相应定义,因此它可以毫无头痛地工作。
答案 1 :(得分:1)
我的班级在这里结识了什么?为什么要附加模板声明?
在您的类中声明的以下表达式是friend declaration:
template<typename TT> SillyClass<TT> friend operator+
(const TT& val, const SillyClass<TT>& other);
上面的表达式将您的类声明为一个重载operator+
系列的朋友,将其左侧参数作为类型TT
并将其右侧作为对象{ {1}}。请注意,这是一个声明而不是定义。也就是说,为了使模板重载SillyClass<TT>
,必须定义它。
对于不同的声明,我有哪些替代方案 导致相同的结果(能够执行3 + a,比如说)?
对于二元运算符,为了使它们对称,必须在类定义之外声明为自由函数,并且为了能够访问其类参数的私有成员,可以将它们声明为相应类的友元函数。
基于这些内容,我将继续以下实施:
operator+