【问题标题】:how do I specialize a bound template friend function to a template class?如何将绑定的模板友元函数专门用于模板类?
【发布时间】:2013-08-19 05:43:30
【问题描述】:

我正在尝试为我创建的模板化堆栈类(作为编程分配)重载输出流运算符 (

我构建了一个更简单的代码示例来演示这个问题。请注意,在示例中,我使用了一个名为“oper()”的函数,而不是使用重载的 operator

    // 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;
}

【问题讨论】:

    标签: c++ templates friend


    【解决方案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 查找找到它们的上下文中创建这些函数,这意味着它不会污染其他上下文,从而简化错误消息(或至少不会使它们进一步复杂化)。

    【讨论】:

    • 非常好。虽然不是我最初想要的,但它比使用绑定的模板朋友要简单得多。谢谢。
    【解决方案2】:

    如果您前向声明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&lt;T&gt; 成为Bigger&lt;T&gt; 的朋友。请注意,语法比大卫的答案复杂得多——我在实践中也是这样做的。

    【讨论】:

    • 这是执行 Petr 建议的 更好 方式,我仍然有不同的偏好,但是 +1
    • @DavidRodríguez-dribeas 实际上,我更喜欢您在答案中给出的风格,这主要是对 OP 似乎试图实现的语法的演示。这是可能的,但并不漂亮。
    • 我认为这是最通用的方式。我的理解,如果您需要在friend 函数中指定默认模板参数,这是唯一的方法。
    • 是的,这正是我所要求的,是的,语法相当复杂!谢谢
    猜你喜欢
    • 2012-01-23
    • 2012-01-21
    • 1970-01-01
    • 2016-10-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-12-19
    相关资源
    最近更新 更多