I'm facing some troubles on my quest on learning C++ template metaprogramming. I'm trying to create some COM+ wrappers so my life mixing them with C++ gets happier :)
My first step was to create a smart pointer which managed COM+ objects through their Release
method:
template <typename COM>
using com_ptr = std::shared_ptr<COM>;
template<class COM>
com_ptr<COM> make_com_ptr(COM **ppv)
{
auto ret = com_ptr<COM>(*ppv, [](COM *p) { if (p) p->Release(); });
*ppv = NULL;
return ret;
}
So far so good, now the tricky bit. (Almost) all COM+ methods which return another COM+ object will return the afore mentioned interface as a pointer to pointer on the method's argument list, like
HRESULT WINAPI IXMLDOMDocument::selectSingleNode(BSTR, IXMLDOMNode**)
I want/need to call some (member)function which could give me that result pointer as its return value, something like this:
IXMLDOMDocument *prawDoc(nullptr);
CoCreateInstance(..., reinterpret_cast<LPVOID*>(&prawDoc));
auto pDoc = make_com_ptr(&prawDoc);
com_ptr<IXMLDOMNode> pNode = FX(pDoc, &IXMLDOMDocument::selectSingleNode,_bstr_t("//xpath"));
^^(auto pNode = ...) ^^ (the function)
Now, what I've got so far:
template<typename COMRET, typename COM, typename METHOD, typename A1>
com_ptr<COMRET> _prv_com_comret(com_ptr<COM> This, const METHOD &Method, A1 Arg1)
{
COMRET *ppv(nullptr);
::SetLastError((*This.*Method)(Arg1, &ppv));
return make_com_ptr(&ppv);
}
#define com_comret( COM, This, Method, ... )\
_prv_com_comret<COM>( This, &decltype(This)::_Ptr_base::element_type::Method, __VA_ARGS__ )
So, with this template function and macro, I could write something like this:
auto pNode = com_comret(IXMLDOMNode, pDoc, selectSingleNode, _bstr_t("//xpath"));
What bothers me about this solution is that I have to specify the return type (IXMLDOMNode
) even though the compiler Does know its type (as everyone would agree, it's the last argument of the IXMLDOMDocument::selectSingleNode
method)
So, in the end, this long post is reduced to: is it posible with some sort of template metaproggraming+macro sorcery to deduce that argument type without having to specify it?
Thanks in advance!!
Open up the pointer-to-member type instead of making it opaque.
template<typename COMRET, typename COM, typename A1>
com_ptr<COMRET> _prv_com_comret(com_ptr<COM> This, COMRET (COM::* const Method)(A1, COMRET**), A1 Arg1)
This should be callable with no template args specified explicitly.