我正在尝试为我创建的模板化堆栈类(作为编程赋值)重载输出流操作符(<<<<我正在使用声明友元运算符的正常范例<<函数到堆栈类。我按照Prata的例子(C ++ primer plus)将“绑定模板友元函数添加到模板类”。代码编译并执行,但是没有给出期望的结果,因为模板化运算符<<当我只希望它重载Stack类的输出流操作符时,函数试图重载main中输出流操作符的每次出现。所以我认为我需要专门化重载运算符<<功能。
我构建了一个更简单的代码示例来演示该问题。请注意,而不是使用重载运算符<<在示例中,我使用了一个名为“oper()”的函数。代码如下(附加),问题是oper()适用于Bigger类(我想要的)和BIG类(我不想要)。你能告诉我如何专门化模板化的oper()函数吗?
// Compiler: gcc
// Purpose: test templates. test bound template friend fns.
#include <iostream>
using namespace std;
// declare template function
template <typename T> std::ostream & oper (std::ostream &os, const T &);
template <typename T> class Bigger {
T value;
public:
Bigger(T init) {value = init;}
// declare bound template friend functions
friend std::ostream &oper<> (std::ostream &os, const Bigger<T> &);
};
class Bad { // but oper() can work with this class too!
int i;
public:
int value;
Bad(): i(1),value(2) {};
};
// define full template functions
// want to specialize this function so that it only works with class Bigger!
template <typename T> std::ostream &oper (std::ostream &os, const T & big) {
os << big.value;
return os;
}
int main (int argc, char * argv[]) {
Bigger <float> bf {3.1};
// this is desired behavior. oper() acts as a friend to Bigger.
cout << "oper bf: "; oper(cout,bf); cout<<endl;
Bad bad;
// this is undesired behavior. template is too loose allowing oper to work for Bad!!!
cout << "oper bad: ";oper(cout,bad);cout<<endl;
return 0;
}
答案 0 :(得分:1)
如何将绑定模板友元函数专门化为模板类?
简单的答案你不能。函数模板只能是完全专业化的,但您要问的是提供类模板的部分特化。最接近的是提供一个不同的基本模板(参见Petr Budnik答案),而不是专门化....但我也不会这样做。
在定义模板的朋友操作符(或一般的朋友函数)时,我不想使用模板,而是将单个非模板操作符定义为模板的朋友。这可以通过在类定义中提供友元函数的定义来实现:
template <typename T>
class MyTemplate {
int data;
//...
friend std::ostream operator<<(std::ostream& os, MyTemplate const& t) {
os << t.data;
return os;
}
};
这种方法有几个优点,第一个是它允许为非模板函数提供通用实现,从而避免了函数模板特化所带来的所有问题(注意:避免专门化功能)模板!)和多个基本功能模板,定义重载,什么不是。同时,它在上下文中创建这些函数,只能通过ADL查找找到它们,这意味着它不会污染其他上下文,从而简化错误消息(或者至少不会使它们进一步复杂化)。
答案 1 :(得分:1)
如果您转发声明Bigger
,那么您可以限制oper
仅适用于Bigger
的特化:
// declare template function
template <typename T> class Bigger;
template <typename T> std::ostream & oper (std::ostream &os, const Bigger<T> &);
template <typename T> class Bigger {
T value;
public:
Bigger(T init) {value = init;}
// declare bound template friend functions
friend std::ostream &oper<> (std::ostream &os, const Bigger &);
};
// define full template functions
template <typename T> std::ostream &oper (std::ostream &os, const Bigger<T> &big) {
os << big.value;
return os;
}
这允许您使用oper
的模板定义,但只允许单一特化oper<T>
成为Bigger<T>
的朋友。请注意,语法比David的答案复杂得多 - 这也是我在实践中也是这样做的。