然后,我决定在类Hen上实现一个特别的"IHenNative"接口,并非所有的使用者都知道它的存在:
class Hen : public Implements<IHen, IHen2, Cloaked<IHenNative>> { };由于Cloaked类模板继承自它的模板参数,所以已存的QueryInterface实现可以继续无缝工作。我已经增加了一点额外的编译时的类型信息,现在我可以查询它们。由此,我会定义一个IsCloaked类型,这样,我就可以很容易的查询任意接口以判断它是否被隐藏:
template <typename Interface> struct IsCloaked : std::false_type {}; template <typename Interface> struct IsCloaked<Cloaked<Interface>> : std::true_type {};现在,我可以使用一个递归的可变函数模板,来计算未隐藏的接口数目:
template <typename First, typename ... Rest> constexpr unsigned CounInterfaces() noexcept { return !IsCloaked<First>::value + CounInterfaces<Rest ...>(); }当然,我需要一个终止函数,可以简单的返回0:
template <int = 0> constexpr unsigned CounInterfaces() noexcept { return 0; }使用现代C++在编译时进行算术计算的强大能力令人目瞪口呆,同时也简单的令人惊叹。现在我通过请求数量来继续完善GetIids的实现:
unsigned const localCount = CounInterfaces<Interfaces ...>();一个不太圆满的地方是,编译器对常量表达式的支持还不是很成熟。尽管,这毫无疑问是一个常量表达式,但是编译器却不会如此看待constexpr成员函数。理想情况下,我可以标识CountInterfaces函数模板为constexpr,同时结果表达式也将是一个常量表达式,但是,编译器不会这认为。另一方面,毋庸置疑,编译器会优化这段代码。现在,不管是什么原因,如果CountInterfaces没有找到隐含接口,GetIids会简单的返回成功,因为结果数组会为空:
if (0 == localCount) { return S_OK; }同样的,这也是一个有效的常量表达式,编译器会无需任何条件的生成代码。换句话说,如果没有未隐藏的接口,剩下的代码会简单的从实现中删除。否则,代码的实现,会强制要求使用传统的COM分配器,分配一个合理大小的GUID数组:
GUID * localArray = static_cast<GUID *>(CoTaskMemAlloc(sizeof(GUID) * localCount));当然,这可能失败,在这种情况下,我简单的返回合适的HRESULT值:
if (nullptr == localArray) { return E_OUTOFMEMORY; }在这点上,GetIids准备好一个数组用来存放GUID。就像你所期待的那样,我需要最后一次枚举接口,然后拷贝每个未隐藏的接口的GUID到这个数组之中。我将使用一组函数模板,就像我之前使用的那样:
template <int = 0> void CopyInterfaces(GUID *) noexcept {} template <typename First, typename ... Rest> void CopyInterfaces(GUID * ids) noexcept { }这个可变模板(第二个函数)可以简单的使用IsCloaked类型来决定,在增加指针之前,是否拷贝由First模板参数标识的接口的GUID。使用这种方式,可以遍历数组,而无需记录它包含多少个元素,或者它将写入数组的哪个位置。我也禁止了关于常量表达式的警告:
#pragma warning(push) #pragma warning(disable:4127) // Conditional expression is constant if (!IsCloaked<First>::value) { *ids++ = __uuidof(First); } #pragma warning(pop) CopyInterfaces<Rest ...>(ids);如你所见,在最后“递归”调用CopyInterfaces使用了可能增加的指针的值。我几乎完成了(整个实现过程)。在返回给调用者之前,GetIids的实现可以通过调用CopyInterfaces来填充数组:
CopyInterfaces<Interfaces ...>(localArray); *count = localCount; *array = localArray; return S_OK; }对于Hen类来说,编译器在它上面的所有操作都是透明的(它完全不知道这些操作):
class Hen : public Implements<IHen, IHen2, Cloaked<IHenNative>> { };这就是一个好的库所应该有的样子。Visual C++ 2015编译器提供了Windows平台下面对于标准C++的完美支持。它允许C++开发者创建优雅而高效的库。这同样支持使用标准C++开发Windows运行时组件,以及完全使用标准C++编写的通用的Windows应用程序。实现类模板仅仅只是现代C++针对Windows运行时的一个例子。(查看 moderncpp.com).