问题
I asked a couple of questions recently on StackOverflow to see if I could consolidate some functions into one by making use of templates. Those questions were:
- Can these methods that convert safe arrays into std::list objects be turned into a template function?
- Can this template function be adapted to account for the following method?
I had one more function to try and update so I thought I would give it a go myself.
This was the function to update:
void CMSATools::ConvertSAFEARRAY_DATE(SAFEARRAY* psaDates, MeetingDates& rMapMeetingDates)
{
DATE *pVals = nullptr;
HRESULT hr = SafeArrayAccessData(psaDates, (void**)&pVals); // direct access to SA memory
if (SUCCEEDED(hr))
{
long lowerBound, upperBound; // get array bounds
hr = SafeArrayGetLBound(psaDates, 1, &lowerBound);
if (FAILED(hr))
throw _com_error(hr);
hr = SafeArrayGetUBound(psaDates, 1, &upperBound);
if (FAILED(hr))
throw _com_error(hr);
long cnt_elements = upperBound - lowerBound + 1;
for (int i = 0; i < cnt_elements; ++i) // iterate through returned values
{
COleDateTime datNotAvailable(pVals[i]);
DWORD dwDatNotAvailable = EncodeMeetingDate(0, datNotAvailable);
rMapMeetingDates[dwDatNotAvailable] = datNotAvailable;
}
hr = SafeArrayUnaccessData(psaDates);
if (FAILED(hr))
throw _com_error(hr);
}
else
{
throw _com_error(hr);
}
hr = SafeArrayDestroy(psaDates);
if (FAILED(hr))
throw _com_error(hr);
}
MeetingDates
is defined like this:
using MeetingDates = std::map<DWORD, COleDateTime>;
So I created this helper function:
template<>
void CMSATools::to_push_back(const DATE& rItem, MeetingDates& rItems)
{
COleDateTime datNotAvailable(rItem);
DWORD dwDatNotAvailable = EncodeMeetingDate(0, datNotAvailable);
rItems[dwDatNotAvailable] = datNotAvailable;
}
And I adjusted my calling code like this:
theApp.MSAToolsInterface().ConvertSAFEARRAY<DATE,MeetingDates>(psaDates, mapMeetingDates);
But when I compile this I now get an error:
5>PublishersDatabaseDlg.obj : error LNK2001: unresolved external symbol "public: static void __cdecl CMSATools::ConvertSAFEARRAY<double,class std::map<unsigned long,class ATL::COleDateTime,struct std::less,class std::allocator<struct std::pair<unsigned long const ,class ATL::COleDateTime> > > >(struct tagSAFEARRAY *,class std::map<unsigned long,class ATL::COleDateTime,struct std::less,class std::allocator<struct std::pair<unsigned long const ,class ATL::COleDateTime> > > &)" (??$ConvertSAFEARRAY@NV?$map@KVCOleDateTime@ATL@@U?$less@K@std@@V?$allocator@U?$pair@$$CBKVCOleDateTime@ATL@@@std@@@4@@std@@@CMSATools@@SAXPAUtagSAFEARRAY@@AAV?$map@KVCOleDateTime@ATL@@U?$less@K@std@@V?$allocator@U?$pair@$$CBKVCOleDateTime@ATL@@@std@@@4@@std@@@Z)
What have I done wrong?
My code so far that won't compile when I make the DATE
... templated call:
template<typename to>
void CMSATools::to_clear(to& rItems)
{
rItems.clear();
}
template<typename from, typename to>
void CMSATools::to_push_back(const from& rItem, to& rItems)
{
rItems.push_back(rItem);
}
template<>
void CMSATools::to_clear(CStringArray& rItems)
{
rItems.RemoveAll();
}
template<>
void CMSATools::to_push_back(const BSTR& rItem, CStringArray& rItems)
{
rItems.Add(rItem);
}
template<>
void CMSATools::to_push_back(const DATE& rItem, MeetingDates& rItems)
{
COleDateTime datNotAvailable(rItem);
DWORD dwDatNotAvailable = EncodeMeetingDate(0, datNotAvailable);
rItems[dwDatNotAvailable] = datNotAvailable;
}
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);
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);
}
I this this answer to a similarly titles question:
Error when pass std::map as template template argument
And I think it might apply in my case but I am not sure how to implement it. If indeed it is the reason.
My header class has this snippet in it:
template<typename to>
static void to_clear(to& rItems);
template<typename from, typename to>
static void to_push_back(const from& rItem, to& rItems);
template<>
static void to_clear(CStringArray& rItems);
template<>
static void to_push_back(const BSTR& rItem, CStringArray& rItems);
template<>
static void to_push_back(const DATE& rItem, MeetingDates& rItems);
template<typename from, typename to>
static void ConvertSAFEARRAY(SAFEARRAY* psaItems, to& rItems);
static DWORD EncodeMeetingDate(int iMeetingType, COleDateTime datMeeting);
At the top of my header file I have:
#pragma once
#include "DemoPickerDlg.h"
#include <map>
#include <vector>
#ifdef _WIN64
#import "..\\..\\MSAToolsLibrary\\MSAToolsLibrary\\bin\\x64\\Release\\MSAToolsLibrary.tlb" raw_interfaces_only named_guids
#else
#import "..\\..\\MSAToolsLibrary\\MSAToolsLibrary\\bin\\x86\\Release\\MSAToolsLibrary.tlb" raw_interfaces_only named_guids
#endif
using MeetingDates = std::map<DWORD, COleDateTime>;
using ListDiscussionItems = std::list<MSAToolsLibrary::IDiscussionItemPtr>;
using ListStudentItems = std::list<MSAToolsLibrary::IStudentItemPtr>;
using ListDutyHistoryLookupItems = std::list<MSAToolsLibrary::IDutyAssignmentLookupPtr>;
来源:https://stackoverflow.com/questions/65592912/i-tried-to-add-a-new-template-helper-function-to-my-class-and-now-i-get-a-lnk200