Continuing our investigation of which C++ COM wrappers support class template argument deduction (CTAD), next up is the C++/WinRT winrt::
.
This one is easy: C++/WinRT’s com_ptr
doesn’t support CTAD, and it doesn’t even try. There is no com_ptr<T>
constructor that takes a T*
. If you want a com_ptr
to copy an existing pointer, you call com_ptr::
:
IWidget* p; winrt::com_ptr<IWidget> smart; smart.copy_from(p);
C++/WinRT eschews the constructor that makes a copy of an inbound pointer on the theory that it’s unclear whether it is taking ownership of the pointer or merely sharing it.
The library author could have provided a deduction guide for the “take ownership” constructor:
template<typename T> com_ptr(T*, take_ownership_from_abi_t) -> com_ptr<T>;
As a consumer, though, you shouldn’t be creating deduction guides for somebody else’s classes. Instead, you can use a maker function.
template<typename T> winrt::com_ptr< std::enable_if_t<std::<is_base_of_v<::IUnknown, T>, T>> make_com_ptr(T* p, winrt::take_ownership_from_abi_t) { return { p, winrt::take_ownership_from_abi }; }
There is some extra magic in the return value to activate the function only if T
derives from ::IUnknown
. This avoids accidentally creating a com_ptr
from a C++/WinRT ABI pointer (which are in the impl
namespace and are therefore off-limits).
If you feel so brave, you can also create a maker function that copies the ABI pointer.
template<typename T> winrt::com_ptr<T> std::enable_if_t<std::<is_base_of_v<::IUnknown, T>, T>> make_com_ptr_from_copy(T* p) { winrt::com_ptr<T> result; result.copy_from(p); return result; }
Bonus chatter: The last time I made a survey of C++ COM wrappers, someone asked me to include C++/CX in the list. But C++/CX doesn’t support wrappers around classic COM interfaces; it supports only Windows Runtime interfaces. Therefore, the answer for C++/CX is always “Not supported. Nothing to see here.”
0 comments