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

VC++
在类VC的界面实现中加入目录树
软件换肤技术在 BCB 中的实现
利用非模窗口生成MDI介面
报表输出轻松搞定
Windows 中不规则窗体的编程实现
解说Win32的窗口子类化
使用测试优先方法开发用户界面
一个简单的登录对话框的实现
一个简单的日记本程序
从资源中加载皮肤
一个在RichEdit中添加表情图象的类
ActiveSkin 4.3 软件换肤在VC中的实现
一种另类“关于(About)”对话框的动态显示方法
对话框打印预览及打印
关于如何换肤、子类化的解决方案
制作 MSN、QQ 的消息提示窗口
如何对 BCGControlBarPro 进行换肤
定制个性化的对话框窗口类
改变窗口中的光标形状
更新MFC中的视图,跟踪.NET Framework中的事件

VC++ 中的 模板友元化


出处:互联网   整理: 软晨网(RuanChen.com)   发布: 2009-10-30   浏览: 56 ::
收藏到网摘: 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只匹配非模