当前位置: 首页 > 图文教程 > 开发语言 > VC++ > 模板友元化

VC++
宏的妙用
泛型编程与设计新思维
C++中的虚函数(一)
C++模板元编程
C++多态技术
通用结构复制函数
<C++实践系列>C++中的虚函数(virtual function)
<C++实践系列>C++中的引用(reference)
<C++实践系列>C++中的异常(exception)
<C++实践系列>C++中的模板(template)
构造函数中的this指针
串行化(Serialization)
二进制浏览、编辑的实现
介绍一个模板动态数组
VC++界面一揽子解决方案(第三版) 介绍
VC++通用GIS功能开发解决方案 2.0v 介绍
确定有穷自动机分析内核
委托、信号和消息反馈的模板实现技术
按照类型名称动态创建对象
Boost中应用的泛型编程技术

VC++ 中的 模板友元化


出处:互联网   整理: 软晨网(RuanChen.com)   发布: 2009-10-30   浏览: 51 ::
收藏到网摘: n/a

模板友元化


原著/Herb Sutter
翻译/宋科


摘要:

    如何将一个函数模板的特化声明为友元呢?标准C++给你提供了两种合法的语法。然而,事实上,对于其中的一种语法,几乎没有编译器对其给予支持;而对于另一种,当前所有主流编译器(除了一款以外)都对其提供了支持。

    假设我们有一个函数模板,可以调用其所操作的对象的SomethingPrivate()方法。特别地,考虑boost::checked_delete()函数模板,它用以删除指定的对象——在它的实现中,会调用该对象的析构函数:

namespace boost { template<typename T> void checked_delete( T* x ) { // ... 其它代码 ... delete x; }} 
现在,假设你想要在一个类中使用该函数模板,则该类中只有一个私有的方法(析构函数):
class Test { ~Test() { } // 私有的!};Test* t = new Test;boost::checked_delete( t ); // 错误:// Test 的析构函数是私有的,// 因此checked_delete不能调用它。 
解决方案很简单:只要令checked_delete()成为Test的友元即可。(其它的方法都需要Test提供公共的析构函数)如何才能实现这个容易的解决方案呢?事实上, C++标准提供了2种方法来合法又便捷的实现它。
本文将提供一个现实的检验:在某个命名空间中,友元化一个模板――说起来容易做起来难!(现实的编译器并未对标准有完好的支持。)

总体来说,我有以下几条好消息和坏消息:
  • 好消息:存在两种对其支持得很好的符合标准的方法,它们的语法很平凡且不会使人困惑。
  • 坏消息:没有哪一种编译器对这两种标准语法提供完全的支持。甚至一些最健壮且几乎完全实现了C++标准的编译器都不能对它们两个或其中之一提供完好的支持。
  • 好消息(重复):我用来测试它的当前的每一个编译器(除了gcc以外)都至少对二者之一有完好的支持。
让我们再多花点儿时间来看看吧。

最初的尝试

本文所述曾经被Stephan Born 在Usenet中作为一个问题提出,他想要做如上的事情。他的问题是,当他尝试将boost::checked_delete()的一个特化声明为Test类的友元时,代码不能被他使用的Microsoft Visual C++ 6.0编译器所接受。

下边是他的源代码:
//例1:授权给友元的方法class Test { ~Test() { } friend void boost::checked_delete( Test* x );}; 
事实上,上述代码不仅不能通过上边所说的编译器的编译,而且不能通过几乎所有的编译器。简单的说,例1的友元声明:
  • 是符合标准的,但却依赖语言的晦涩之处。
  • 是被当前大多数编译器所拒绝的,包括一些很好的编译器。
  • 是容易被修复成不依赖于此晦涩之处的,而且可以通过当前的所有编译器,除了gcc。
我将要深入研究解释C++语言提供给你用来声明友元的四种方法。那是容易的。我也会给你看一些现实中的编译器处理它的有趣的东西,并提出一个方针来实现最便捷的代码,来结束本文。

为什么合法但却晦涩

C++标准的第14.5.3条列举了四条声明友元的规则,归结如下:
  • 1、如果该友元的名字是一个具有确切的模板参数的特化了的模板名字(例如:Name<SomeType>) 

    则,友元就是此模板的特化。
  • 2、否则,如果该友元在某个类或者命名空间(例如:Some::Name)中,而且该类或者命名空间包含一个匹配的非模板函数,

    则,友元就是该函数。
  • 3、否则,如果该友元是在某个类或者命名空间(例如:Some::Name)中的,而且该类或者命名空间包含一个匹配的模板函数(具有适当的模板参数)

    则,友元就是该函数模板的特化。
  • 4、否则,该友元必须在全局命名空间内(unqualified。译者:我将unqualified理解为处于全局命名空间,不知对否。),而且声明为(或重新声明)一个常规函数(非模板)。
很明显,#2和#4只匹配非模