Visual C++ 2015 引入更新的 C++ 特性到 Windows API(4)

IsInspectable 也是基于is_base_of特性的,但是当前适用于匹配接口。如果没找到基于IInspectable 的接口则终止:

template <int = 0> constexpr bool IsInspectable() noexcept {   return false; }

我会禁用掉稀奇古怪的默认参数。假定 IsInspectable 返回的是 true,我需要找到第一个IInspectable-based 接口:

template <int = 0> void * FindInspectable() noexcept {   return nullptr; } template <typename First, typename ... Rest> void * FindInspectable() noexcept {   // Find somehow }

再次使用 is_base_of 特性,但这次要返回一个真实匹配的接口指针:

#pragma warning(push) #pragma warning(disable:4127) // conditional expression is constant if (std::is_base_of<::IInspectable, First>::value) {   return static_cast<First *>(this); } #pragma warning(pop) return FindInspectable<Rest ...>();

BaseQueryInterface 这时可以利用IsInspectable 和 FindInspectable 一起来支持查询 IInspectable:

if (IsInspectable<Interfaces ...>() &&    id == __uuidof(::IInspectable)) {   return FindInspectable<Interfaces ...>(); }

然后指定具体的 Hen 类:

class Hen : public Implements<IHen, IHen2> { };

实现类的模板,可以确保编译器能生成更高效的代码,不管 IHen、Hen2 来自 IInspectable 还是 IIUnknown (或者其他接口)。现在,我可以最后实现 QueryInterface 的递归部分,以及任何追加的接口,例如上面例子中的 IHen2。BaseQueryInterface 是靠调用 FindInterface 函数模板结束的: 

template <typename First, typename ... Rest> void * BaseQueryInterface(GUID const & id) noexcept {   if (id == __uuidof(First) || id == __uuidof(::IUnknown))   {     return static_cast<First *>(this);   }   if (IsInspectable<Interfaces ...>() &&      id == __uuidof(::IInspectable))   {     return FindInspectable<Interfaces ...>();   }   return FindInterface<Rest ...>(id); }

注意,我调用这个FindInterface函数模板,大致等同于我原来调用的BaseQueryInterface,在这个例子中,我向它传递接口的其余部分。我特意再次扩大参数包,这样它可以在列表的其余部分识别第一接口。但会提示一个故障。由于模板参数包不是以函数实参来扩展的,这可能会变得棘手,编程语言写不出来我想要的。更多的时候,这种“递归的”FindInterface可变模板正是你想要的:

template <typename First, typename ... Rest> void * FindInterface(GUID const & id) noexcept {   if (id == __uuidof(First))   {     return static_cast<First *>(this);   }   return FindInterface<Rest ...>(id); }

它会从模板参数的其余部分中分离,如果有匹配就返回调整过的接口指针。另外,它也会调用自己,直到list取完。当我笼统地提及编译期递归时,重要的是要注意这个函数模板,以及其他类似的实现类模板的例子,在技术上递归,而不是在编译期。每个函数模板的实例调用不同的函数模板的实例。例如,FindInterface<IHen, IHen2> 调用 FindInterface<IHen2>, FindInterface<IHen2>调用 FindInterface<>。为了让它递归, FindInterface<IHen, IHen2>不需要调用FindInterface<IHen, IHen2>。

尽管如此,还是要记住,这样的“递归”发生在编译时,它就像你自己手写的一条条if语句。但是,现在,我遇到麻烦了。这个序列如何终止呢?当然是当模板参数列表为空的时候。这个问题在于C++已经定义了空模板参数列表的含义:

template <> void * FindInterface(GUID const &) noexcept {   return nullptr; }

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/e72489af08f8fb85966939de82b5812b.html