Search code examples
c++winapitemplate-meta-programmingcom+

C++ COM+ method argument deduction


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!!


Solution

  • 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.