问题
I have the following template class and template function which intends to access the class' private data member:
#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;
}
To declare the two functions as MyVar<T>
's friend functions, I've tried the following ways inside the declaration of template<class T> class MyVar
to declare friendship. None of them works. How should I do?
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
回答1:
The simplest option is to define the friend within the 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;
}
};
The downside is that the functions can only be called through argument-dependent lookup. That's not a problem in your example, but might be a problem if they don't have a suitable argument, or you want to specify the name without calling it.
If you want a separate definition, then the template will have to be declared before the class definition (so it's available for a friend declaration), but defined afterwards (so it can access the class members). The class will also have to be declared before the function. This is a bit messy, so I'll only show one of the two functions:
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;
}
回答2:
I managed to get the following work
#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 talks about a similar case with operators under "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-definedFoo<T>
Such operator can be defined in the class body, which has the effect of generating a separate non-template
operator<<
for eachT
and makes that non-templateoperator<<
a friend of itsFoo<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 ofoperator<<
for itsT
回答3:
This one compiles on MSVC2013. Basicly adds the forward declarations to class and functions before the 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;
}
回答4:
Well there is a solution that is both simple and involving separation between declaration & definition of the friend function. In the declaration of the friend function (inside the class) you have to give a different template param from the one the class accepts (and it make sense cause this function is not a member of this 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) {
}
No forward declaration needed, as well as there is a separation of declaration & definition.
来源:https://stackoverflow.com/questions/30439805/template-friend-functions-of-template-class