首页 文章

模板类的模板友元函数

提问于
浏览
4

我有以下模板类和模板函数,它打算访问类的私有数据成员:

#include <iostream>

template<class T>
class MyVar
{
    int x;
};

template<class T>
void printVar(const MyVar<T>& var)
{
    std::cout << var.x << std::endl;
}

template<class T>
void scanVar(MyVar<T>& var)
{
    std::cin >> var.x;
}

struct Foo {};

int main(void)
{
    MyVar<Foo> a;
    scanVar(a);
    printVar(a);
    return 0;
}

要将这两个函数声明为 MyVar<T> 's friend functions, I' ve,请在 template<class T> class MyVar 声明中尝试以下方式来声明友谊 . 它们都不起作用 . 我应该怎么做?

template<class T> friend void printVar(const MyVar&);
template<class T> friend void scanVar(MyVar&);
// compilation error

template<class T> friend void printVar(const MyVar<T>&);
template<class T> friend void scanVar(MyVar<T>&);
// compilation error

friend void printVar(const MyVar<T>&);
friend void scanVar(MyVar<T>&);
// link error

friend void printVar(const MyVar&);
friend void scanVar(MyVar&);
// link error too

3 回答

  • 4

    这个编译在MSVC2013上 . 基本上在朋友之前将前向声明添加到类和函数中

    template<class T>   class MyVar ; // class forward declaration
    
    template<class T> ; // function forward declarations
    void printVar(const MyVar<T>& var);
    template<class T>
    void scanVar(MyVar<T>& var);
    
    template<class T>
    class MyVar
    {
        friend void printVar<T>(const MyVar<T>&);
        friend void scanVar<T>(MyVar<T>&);
        int x;
    };
    
    template<class T>
    void printVar(const MyVar<T>& var)
    {
        std::cout << var.x << std::endl;
    }
    
    template<class T>
    void scanVar(MyVar<T>& var)
    {
        std::cin >> var.x;
    }
    
    struct Foo {};
    
    int main1(void)
    {
        MyVar<Foo> a;
        scanVar(a);
        printVar(a);
        return 0;
    }
    
  • 2

    最简单的选择是在类中定义朋友:

    template<class T>
    class MyVar
    {
        int x;
    
        friend void printVar(const MyVar & var) {
            std::cout << var.x << std::endl;
        }
        friend void scanVar(MyVar & var) {
            std::cin >> var.x;
        }
    };
    

    缺点是函数只能通过依赖于参数的查找来调用 . 这在您的示例中不是问题,但如果它们没有合适的参数,或者您希望在不调用它的情况下指定名称,则可能会出现问题 .

    如果你想要一个单独的定义,那么模板必须在类定义之前声明(因此它可用于朋友声明),但之后定义(因此它可以访问类成员) . 该类也必须在函数之前声明 . 这有点乱,所以我只展示这两个函数中的一个:

    template <typename T> class MyVar;
    template <typename T> void printVar(const MyVar<T> & var);
    
    template<class T>
    class MyVar
    {
        int x;
    
        friend void printVar<T>(const MyVar<T> & var);
    };
    
    template <typename T> void printVar(const MyVar<T> & var) {
        std::cout << var.x << std::endl;
    }
    
  • 1

    我成功完成了以下工作

    #include <iostream>
    
    template<class T>
    class MyVar;
    
    template<class T>
    void printVar(const MyVar<T>& var);
    
    template<class T>
    void scanVar(MyVar<T>& var);
    
    template<class T>
    class MyVar
    {
        int x;
        friend void printVar<T>(const MyVar<T>& var);
        friend void scanVar<T>(MyVar<T>& var);
    };
    
    template<class T>
    void printVar(const MyVar<T>& var)
    {
        std::cout << var.x << std::endl;
    }
    
    template<class T>
    void scanVar(MyVar<T>& var)
    {
        std::cin >> var.x;
    }
    
    struct Foo {};
    
    int main(void)
    {
        MyVar<Foo> a;
        scanVar(a);
        printVar(a);
        return 0;
    }
    

    UPDhttp://en.cppreference.com/w/cpp/language/friend在"Template friend operators"下与运营商讨论类似案例:

    模板朋友的一个常见用例是声明一个非成员运算符重载,该重载作用于类模板,例如: operator <<(std :: ostream&,const Foo <T>&)用于某些用户定义的Foo <T>这样的运算符可以在类体中定义,它具有生成单独的非模板运算符<< for的效果每个T并使非模板运算符<<其Foo <T>的朋友...或者函数模板必须在类主体之前声明为模板,在这种情况下,Foo <T>中的友元声明可以请参阅operator <<的完整特化

相关问题