简体   繁体   English

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

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

I am trying to overload the output stream operator (<<) for a templated stack class I created (as a programming assignment). 我正在尝试为我创建的模板堆栈类(作为编程分配)重载输出流运算符(<<)。 I am using the normal paradigm of declaring an friend operator<< function to the stack class. 我使用的正常范式是向堆栈类声明一个friend operator <<函数。 I followed Prata's example (C++ primer plus) of "bound template friend functions to a template class". 我遵循了Prata的示例(C ++入门指南加上)“将模板好友函数绑定到模板类”。 The code compiles and executes, but doesn't give the desired result because the templated operator<< function is attempting to overload every occurrence of the output stream operator in main, when I only want it to overload the output stream operators for the Stack class. 代码会编译并执行,但未给出期望的结果,因为模板化的operator <<函数试图重载main中每次出现的输出流运算符,而我只希望它重载Stack类的输出流运算符。 So I think that I need to specialize the overloaded operator<< function. 因此,我认为我需要专门处理重载的operator <<函数。

I constructed a simpler code example to demonstrate the problem. 我构建了一个更简单的代码示例来演示该问题。 Please note that rather than using an overloaded operator<< in the example, I use a function called "oper()". 请注意,我没有使用示例中的重载运算符<<,而是使用了一个名为“ oper()”的函数。 The code follows (attached too), The problem is that oper() works for both the Bigger class (which I want) AND the BIG class (which I dont want). 代码如下(也附带了),问题在于oper()可同时用于Bigger类(我想要的)和BIG类(我不需要的)。 Can you show me how to specialize the templated oper() function? 您能告诉我如何专门化模板化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;
}

how do I specialize a bound template friend function to a template class? 如何将绑定的模板好友功能专门化为模板类?

Simple answer you cannot. 简单的答案,你不能。 Function templates can only be fully specialized, but what you are asking is to provide something alike a partial specialization of class templates. 函数模板只能完全专业化,但是您要提供的是类似于类模板的部分专业化功能。 The closest thing would be to provide a different base template (see Petr Budnik answer) rather than specializing.... but I would not do that either. 最接近的事情是提供一个不同的基础模板(请参见Petr Budnik的答案)而不是专门化...。但是我也不会这样做。

When defining friend operators (or friend functions in general) of a template, I prefer not to use templates, but define a single non-template operator as the friend of the template. 在定义模板的好友运算符(或通常的好友函数)时,我不喜欢使用模板,而是将单个非模板运算符定义为模板的好友。 This can be achieved in the language by providing the definition of the friend function inside the class definition: 通过在类定义内提供friend函数的定义 ,可以用该语言实现:

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

There are a couple of advantages to this approach, the first of which is that it allows to provide a generic implementation for a non-template function, and thus avoids all issues that arise with function template specializations (note: avoid specializing function templates!) and multiple base function templates that define overloads, and what not. 此方法有两个优点,第一个优点是它允许为非模板函数提供通用实现,从而避免了函数模板专门化带来的所有问题(注意:避免对函数模板进行专门化!)以及定义重载的多个基本函数模板,以及没有的。 At the same time, it creates those functions in a context where they can only be found through ADL lookup, which means that it won't pollute other contexts and will thus simplify error messages (or at least not complicate them further). 同时,它在只能通​​过ADL查找找到它们的上下文中创建这些函数,这意味着它不会污染其他上下文,从而简化了错误消息(或至少不会使它们进一步复杂化)。

If you forward-declare Bigger then you can restrict oper to work only on specializations of Bigger : 如果您向前声明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;
}

This allows you to use a template definition for oper but only make the single specialization oper<T> be a friend to Bigger<T> . 这允许您对oper使用模板定义,但仅使单个专业化oper<T>Bigger<T>成为朋友。 Note that the syntax is much more complicated than David's answer - which is how I also do this in practice. 请注意,语法比David的答案要复杂得多-这也是我在实践中也是这样做的方式。

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

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