繁体   English   中英

如何将绑定的模板好友功能专门化为模板类?

[英]how do I specialize a bound template friend function to a template class?

我正在尝试为我创建的模板堆栈类(作为编程分配)重载输出流运算符(<<)。 我使用的正常范式是向堆栈类声明一个friend operator <<函数。 我遵循了Prata的示例(C ++入门指南加上)“将模板好友函数绑定到模板类”。 代码会编译并执行,但未给出期望的结果,因为模板化的operator <<函数试图重载main中每次出现的输出流运算符,而我只希望它重载Stack类的输出流运算符。 因此,我认为我需要专门处理重载的operator <<函数。

我构建了一个更简单的代码示例来演示该问题。 请注意,我没有使用示例中的重载运算符<<,而是使用了一个名为“ 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;
}

如何将绑定的模板好友功能专门化为模板类?

简单的答案,你不能。 函数模板只能完全专业化,但是您要提供的是类似于类模板的部分专业化功能。 最接近的事情是提供一个不同的基础模板(请参见Petr Budnik的答案)而不是专门化...。但是我也不会这样做。

在定义模板的好友运算符(或通常的好友函数)时,我不喜欢使用模板,而是将单个非模板运算符定义为模板的好友。 通过在类定义内提供friend函数的定义 ,可以用该语言实现:

template <typename T>
class MyTemplate {
   int data;
//...
   friend std::ostream operator<<(std::ostream& os, MyTemplate const& t) {
       os << t.data;
       return os;
   }
};

此方法有两个优点,第一个优点是它允许为非模板函数提供通用实现,从而避免了函数模板专门化带来的所有问题(注意:避免对函数模板进行专门化!)以及定义重载的多个基本函数模板,以及没有的。 同时,它在只能通​​过ADL查找找到它们的上下文中创建这些函数,这意味着它不会污染其他上下文,从而简化了错误消息(或至少不会使它们进一步复杂化)。

如果您向前声明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的答案要复杂得多-这也是我在实践中也是这样做的方式。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM