章节名:类模板的嵌套类中的友元声明(friend declarations in a class nested inside a class template)
2012-09-02 12:15:00
日志无法插代码,弄到这里来好了。也确实引用了这边的不少内容w
C++ Primer上有说类模板的嵌套类,有说类模板的友元声明,但是没有说嵌套类中的友元声明(如果不是我没找到的话……)。
最开始的写法如下,是想把Linked_list类的成员函数NodePtr_to_iter和iter_to_NodePtr设为嵌套类iter的友元:
template <typename T> class Linked_list
{
protected:
struct Node
{
//...
};
class iter //iter is implemented in terms of Node*, and supports arithmetic operations
{
public:
iter() : ptr(NULL)
{}
//...
private:
explicit iter(Node* nP) : ptr(nP)
{}
private:
Node *ptr;
//friends:
friend iter NodePtr_to_iter(Node* const nP);
friend Node* iter_to_NodePtr(const iter it);
};
iter NodePtr_to_iter(Node* const nP)
{ return iter(nP); }
Node* iter_to_NodePtr(const iter it)
{ return it.ptr; }
public:
//...
protected:
//...
};
结果是编译不通过,成员不可访问。
ICC:
warning #1624: "Linked_list<T>::iter NodePtr_to_iter(Linked_list<T>::Node *)" declares a non-template function -- add <> to refer to a template instance
error #373: "Linked_list<T>::iter::iter(Linked_list<T>::Node *) [with T=Term]" (declared at line 55) is inaccessible
VC++:
error C2248: 'Linked_list<T>::iter::iter' : cannot access private member declared in class 'Linked_list<T>::iter'
原因C++P上有说——
If we have not previously told the compiler that the friend is a template, then the compiler will infer that the friend is an ordinary nontemplate class or function.
如果没有事先告诉编译器该友元是一个模板,则编译器将认为该友元是一个普通非模板类或非模板函数。引自 类模板的嵌套类中的友元声明(friend declarations in a class nested inside a class template)
A friend declaration introduces the named class or nonmember function into the surrounding scope. Moreover, a friend function may be defined inside the class. The scope of the function is exported to the scope enclosing the class definition.
友元声明将已命名的类或非成员函数引入到外围作用域中。此外,友元函数可以在类的内部定义,该函数的作用域扩展到包围该类定义的作用域。引自 类模板的嵌套类中的友元声明(friend declarations in a class nested inside a class template)
Linked_list<char>::Node* pNode = iter_to_NodePtr(list.find('w')); //returned type of find() is iterator
VC++编译不通过:
error C2248: 'Linked_list<T>::Node' : cannot access protected struct declared in class 'Linked_list<T>'
ICC编译通过且工作正常,但有警告:
warning #525: class "Linked_list<T>::Node [with T=char]" (declared at line 10 of "...\Linked_list.h") is an inaccessible type (allowed for cfront compatibility)
受保护的Linked_list<T>::Node现在可以访问了!!不过提示中的(allowed for cfront compatibility)很让人在意,看起来这是一个已经被废弃的特性。
////////////////////////////////////////////////!!!怒球相关资料!!!////////////////////////////////////////////////
接下来是得到正确写法的过程。
比较难办的问题是:外围类的成员函数同时也是函数模板,同时,我们只想将iter<T>(某个实例)的友元关系授予给Linked_list<T>::NodePtr_to_iter(具有相同实参的实例)。但无论如何,因为:
to make a member function a friend, the class containing that member must have been defined.
必须先定义包含成员函数的类,才能将成员函数设为友元。
When we want to restrict friendship to a specific instantiation, then the class or function must have been declared before it can be used in a friend declaration
想要限制对特定实例化的友元关系时,必须在可以用于友元声明之前声明类或函数引自 类模板的嵌套类中的友元声明(friend declarations in a class nested inside a class template)
template <typename T> class Linked_list
{
protected:
struct Node
{
//...
};
class iter;
iter NodePtr_to_iter(Node* const nP);
Node* iter_to_NodePtr(const iter it);
class iter //iter is implemented in terms of Node*, and supports arithmetic operations
{
public:
iter() : ptr(NULL)
{}
//...
private:
explicit iter(Node* nP) : ptr(nP)
{}
private:
Node *ptr;
//friends:
friend iter Linked_list::NodePtr_to_iter(Node* const nP);
friend Node* iter_to_NodePtr<T>(const iter it);
};
public:
//...
protected:
//...
};
于是我们收到了了来自编译器的友情提示:
error : iter_to_NodePtr is not a template
error #308: member "Linked_list<T>::iter::ptr [with T=Term]" (declared at line 59 of "...\Linked_list.h") is inaccessible
事后想来确实合情合理,在其他地方我们也从来都不能通过显式实参直接指定类模板成员函数的实例,而是通过类模板实例的作用域限定符来指定的。
同时我们还知道了:嵌套类将外部类的成员函数设为友元,只要该成员函数的声明在嵌套类定义之前就可。同时需要注意的是因为成员函数的声明用到了iter,所以iter应该在之前做前向声明。
于是我们得到最后的正确写法(加上static是为了满足其它需要):
template <typename T> class Linked_list
{
protected:
struct Node
{
//...
};
class iter;
static iter NodePtr_to_iter(Node* const nP);
static Node* iter_to_NodePtr(const iter it);
class iter //iter is implemented in terms of Node*, and supports arithmetic operations
{
public:
iter() : ptr(NULL)
{}
//...
private:
explicit iter(Node* nP) : ptr(nP)
{}
private:
Node *ptr;
//friends:
friend iter Linked_list::NodePtr_to_iter(Node* const nP);
friend Node* Linked_list::iter_to_NodePtr(const iter it);
};
public:
//...
protected:
//...
};
template <typename T> inline typename Linked_list<T>::iter Linked_list<T>::NodePtr_to_iter(Node* const nP)
{ return iter(nP); }
template <typename T> inline typename Linked_list<T>::Node* Linked_list<T>::iter_to_NodePtr(const iter it)
{ return it.ptr; }