31.5.3. 特化标准库
至此一切顺利,但是没人会喜欢这样编写客户端代码:
ACE_Message_Queue<ACE_NULL_SYNCH> mq; // 2 locks; total 120 bytes char results[120]; acestl::message_queue_sequence<ACE_NULL_SYNCH> mqs(mq); acestl::message_queue_sequence<ACE_NULL_SYNCH>::fast_copy(mqs.begin() , mqs.end(), &results[120]); |
当另一个迭代器类型是char (const)*,我们希望std::copy()能够自动使用快速版本。为此需要特化std::copy()。
出于种种原因,在std名字空间定义模板偏特化是被禁止的行为。已证明该禁令会在两种情况下带来不便。第一点,也是最重要的一点,message_queue_sequence是模板,我们希望迎合各种特化方式,所以希望做些如清单31.13所示的事情。(简洁起见,这里我省略了每个message_queue_sequence<S>::iterator之前的名字空间修饰acestl,以后也是如此。)
清单 31.13. 特化std::copy() 的非法方式
// In namespace std template <typename S> char* copy( typename message_queue_sequence<S>::iterator from , typename message_queue_sequence<S>::iterator to, char* o) { return message_queue_sequence<S>::fast_copy(from, to, o); } template <typename S> typename message_queue_sequence<S>::iterator copy(char* from, char* to , typename message_queue_sequence<S>::iterator o) { return message_queue_sequence<S>::fast_copy(from, to, o); }
|
因为我们不能这么干,所以不得不预测message_queue_sequence的各种特化,然后为std::copy()编写相应的(全)特化版本,如清单31.14所示。注意为了确保从char*和char const*的拷贝都使用优化的块传输方式,需要单独为它们各自准备特化版本。
清单 31.14. 特化std::copy() 的合法方式
Code View: Scroll / Show All // In namespace std template <> char* copy( typename message_queue_sequence<ACE_NULL_SYNCH>::iterator from , typename message_queue_sequence<ACE_NULL_SYNCH>::iterator to , char* o) { return message_queue_sequence<ACE_NULL_SYNCH>::fast_copy(from, to, o); } . . . // Same as above, but for ACE_MT_SYNCH
template <> typename message_queue_sequence<ACE_NULL_SYNCH>::iterator copy(char* from , char* to , typename message_queue_sequence<ACE_NULL_SYNCH>::iterator o) { return message_queue_sequence<ACE_NULL_SYNCH>::fast_copy(from, to, o); } . . . // Same as above, but for ACE_MT_SYNCH
template <> typename message_queue_sequence<ACE_NULL_SYNCH>::iterator copy(char const* from , char const* to , typename message_queue_sequence<ACE_NULL_SYNCH>::iterator o) { return message_queue_sequence<ACE_NULL_SYNCH>::fast_copy(from, to, o); } . . . // Same as above, but for ACE_MT_SYNCH
|
幸运的是,ACE只提供了两种特化方式,第一种是ACE_NULL_SYNCH(展开为“ACE_Null_Mutex, ACE_Null_Condition”的宏定义),另一种是ACE_MT_SYNCH(展开为“ACE_Thread_Mutex, ACE_Condition_Thread_Mutex”的宏定义),所以最后产生的特化版本只有六个。
但还不止这些。如果你和我一样,不愿意用char代替C++(www.cppentry.com)所缺少的字节数据类型,那么大概会转而使用signed char和unsigned char,不过在解析函数(以及模板)重载时,它们和char都是不同的类型。直接将其传入std::copy()不能触发优化后的传输方法。所以没办法,我们还要再给signed char和unsigned char各提供六个特化,最后总共是18个,而如果我们能够在std名字空间使用偏特化,达到同样的目的只要两个,最多三个特化就行了。
所幸这些努力还是值得付出的。在我们观看结果之前,我先回答一个可能已经在你脑海盘旋的问题:为什么只关心std::copy()?原则上应当特化所有可能的标准算法,但我没有这么做有两方面的原因。首先,退一万步讲,全部特化终究是件很麻烦的事情;为了避免大量的手工活,我们实际上不得不借助宏,但有谁喜欢宏呢?第二个理由更充分,我们编写这么多的特化无非是为了性能,希望不论是在原始内存块中进行的数据译码,还是到新存储空间的数据交换都能快速进行。而依我的经验,这两种操作都使用std::copy()。我得承认有个例外,我们的中间件项目还用到了copy_n()。这是一个被忽视的算法,因此遗漏在C++(www.cppentry.com)-98之外(但会进入下个标准版本),所以出现在STLSoft中。copy_n()也有相应的特化版本,但这次是在名字空间stlsoft,特化方式和std::copy()一样。因此,共有36个函数特化版本定义于头文件<acestl/collections/message_queue_sequence.hpp>。
【责任编辑:
董书 TEL:(010)68476606】