Reputation: 19197
This question is a followon to this one:
This is my new template function:
template<typename from, typename to>
void CMSATools::ConvertSAFEARRAY(SAFEARRAY* psaItems, to& rItems)
{
from* pVals = nullptr;
HRESULT hr = SafeArrayAccessData(psaItems, (void**)&pVals); // direct access to SA memory
if (SUCCEEDED(hr))
{
long lowerBound, upperBound; // get array bounds
hr = SafeArrayGetLBound(psaItems, 1, &lowerBound);
if (FAILED(hr))
throw _com_error(hr);
hr = SafeArrayGetUBound(psaItems, 1, &upperBound);
if (FAILED(hr))
throw _com_error(hr);
rItems.clear();
long cnt_elements = upperBound - lowerBound + 1;
for (int i = 0; i < cnt_elements; ++i) // iterate through returned values
{
rItems.push_back(pVals[i]);
}
hr = SafeArrayUnaccessData(psaItems);
if (FAILED(hr))
throw _com_error(hr);
}
else
{
throw _com_error(hr);
}
hr = SafeArrayDestroy(psaItems);
if (FAILED(hr))
throw _com_error(hr);
}
I have this other method that I would like to be able to use with the template function above:
void CMSATools::ConvertSAFEARRAY_BSTR(SAFEARRAY* psaStrings, CStringArray& rAryStrings)
{
BSTR *pVals = nullptr;
HRESULT hr = SafeArrayAccessData(psaStrings, (void**)&pVals); // direct access to SA memory
if (SUCCEEDED(hr))
{
long lowerBound, upperBound; // get array bounds
hr = SafeArrayGetLBound(psaStrings, 1, &lowerBound);
if (FAILED(hr))
throw _com_error(hr);
hr = SafeArrayGetUBound(psaStrings, 1, &upperBound);
if(FAILED(hr))
throw _com_error(hr);
rAryStrings.RemoveAll();
long cnt_elements = upperBound - lowerBound + 1;
for (int i = 0; i < cnt_elements; ++i) // iterate through returned values
{
CString strPublisher(pVals[i]);
rAryStrings.Add(strPublisher);
}
hr = SafeArrayUnaccessData(psaStrings);
if (FAILED(hr))
throw _com_error(hr);
}
else
{
throw _com_error(hr);
}
hr = SafeArrayDestroy(psaStrings);
if (FAILED(hr))
throw _com_error(hr);
}
from
is easy: BSTR
.to
is easy: CStringArray
.The problem is that all of the other parameters were derived from std::list
and we used push_back
. In this instance, when it is of type CStringArray
I need to use Add(...)
(and also create the CString
element first).
I see lots of suggestions here but it is not clear to me what the simplest approach should be.
It seems I should be able to is: std::is_same<from,CStringArray>::value
to see if they are the same, but the answers seem to frown on using this approach.
Upvotes: 1
Views: 57
Reputation: 17668
Complications in this case are the clear
and push_back
calls which CStringArray
does not implement. While both can be solved generically as described in Templated check for the existence of a class member function? for example, a simpler approach can work to cover just the proposed case by using a couple of helper function templates.
// default implementations for <T, std::list<T>>
template<typename to>
void to_clear(to &rItems)
{ rItems.clear(); }
template<typename from, typename to>
void to_push_back(const from &rItem, to &rItems)
{ rItems.push_back(rItem); }
// specializations for <BSTR, CStringArray>
template<>
void to_clear(CStringArray &rItems)
{ rItems.RemoveAll(); }
template<>
void to_push_back(const BSTR &rItem, CStringArray &rItems)
{ rItems.Add(rItem); } // implicit CString conversion
// e.g. ConvertSAFEARRAY<int, std::list<int>>
// ConvertSAFEARRAY<IDiscussionItemPtr, ListDiscussionItems>
// ConvertSAFEARRAY<BSTR, CStringArray>
template<typename from, typename to>
void ConvertSAFEARRAY(SAFEARRAY* psaItems, to& rItems)
{
from* pVals = nullptr;
HRESULT hr = SafeArrayAccessData(psaItems, (void**)&pVals); // direct access to SA memory
if (SUCCEEDED(hr))
{
long lowerBound, upperBound; // get array bounds
hr = SafeArrayGetLBound(psaItems, 1, &lowerBound);
if (FAILED(hr))
throw _com_error(hr);
hr = SafeArrayGetUBound(psaItems, 1, &upperBound);
if (FAILED(hr))
throw _com_error(hr);
to_clear<to>(rItems);
long cnt_elements = upperBound - lowerBound + 1;
for (int i = 0; i < cnt_elements; ++i) // iterate through returned values
{
to_push_back<from, to>(pVals[i], rItems);
}
hr = SafeArrayUnaccessData(psaItems);
if (FAILED(hr))
throw _com_error(hr);
}
else
{
throw _com_error(hr);
}
hr = SafeArrayDestroy(psaItems);
if (FAILED(hr))
throw _com_error(hr);
}
Upvotes: 1