模板的模板友元函数 class

template friend functions of template class

我有以下模板 class 和旨在访问 class' 私有数据成员的模板函数:

#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>的友元函数,我在template<class T> class MyVar的声明中尝试了以下方法来声明友元。 None 其中有效。我该怎么办?

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

我成功完成了以下工作

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

UPD: http://en.cppreference.com/w/cpp/language/friend 与 "Template friend operators":

下的运算符讨论了类似的情况

A common use case for template friends is declaration of a non-member operator overload that acts on a class template, e.g. operator<<(std::ostream&, const Foo<T>&) for some user-defined Foo<T>

Such operator can be defined in the class body, which has the effect of generating a separate non-template operator<< for each T and makes that non-template operator<< a friend of its Foo<T>

...

or the function template has to be declared as a template before the class body, in which case the friend declaration within Foo<T> can refer to the full specialization of operator<< for its T

这个是在MSVC2013上编译的。基本上将前向声明添加到 class 并在 friend

之前运行
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;
}

最简单的选项是在 class:

中定义好友
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;
    }
};

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

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

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

好吧,有一个解决方案既简单又涉及友元函数的声明和定义之间的分离。在 friend 函数的声明中(在 class 内),你必须给出一个与 class 接受的模板参数不同的模板参数(这是有道理的,因为这个函数不是这个 class).

template<class T>
class MyVar
{
    int x;

    template<typename Type>
    friend void printVar(const MyVar<Type> & var);

    template<typename Type>
    friend void scanVar(MyVar<Type> & var);
};

template<typename T>
void printVar(const MyVar<T> & var) {

}

template<typename T>
void scanVar(MyVar<T> & var) {

}

不需要前向声明,并且声明和定义是分开的。