我试图向我的班级添加一个新的模板辅助函数,但现在出现 LNK2001 错误.怎么修? [英] I tried to add a new template helper function to my class and now I get a LNK2001 error. How to fix?

查看:47
本文介绍了我试图向我的班级添加一个新的模板辅助函数,但现在出现 LNK2001 错误.怎么修?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我最近在 StackOverflow 上问了几个问题,看看我是否可以通过使用模板将一些功能合并为一个.这些问题是:

  1. 这些将安全数组转化为 std::list 对象的方法能否转化为模板函数?
  2. 这个模板函数能否适应以下方法?

我还有一个功能要尝试和更新,所以我想自己试一试.

这是要更新的函数:

void CMSATools::ConvertSAFEARRAY_DATE(SAFEARRAY* psaDates, MeetingDates& rMapMeetingDates){日期 *pVals = nullptr;HRESULT hr = SafeArrayAccessData(psaDates, (void**)&pVals);//直接访问SA内存如果(成功(小时)){长下界,上界;//获取数组边界hr = SafeArrayGetLBound(psaDates, 1, &lowerBound);如果(失败(小时))抛出_com_error(hr);hr = SafeArrayGetUBound(psaDates, 1, &upperBound);如果(失败(小时))抛出_com_error(hr);long cnt_elements = upperBound -lowerBound + 1;for (int i = 0; i < cnt_elements; ++i)//遍历返回值{COleDateTime datNotAvailable(pVals[i]);DWORD dwDatNotAvailable = EncodeMeetingDate(0, datNotAvailable);rMapMeetingDates[dwDatNotAvailable] = datNotAvailable;}hr = SafeArrayUnaccessData(psaDates);如果(失败(小时))抛出_com_error(hr);}别的{抛出_com_error(hr);}hr = SafeArrayDestroy(psaDates);如果(失败(小时))抛出_com_error(hr);}

MeetingDates 定义如下:

 using MeetingDates = std::map;

所以我创建了这个辅助函数:

模板<>void CMSATools::to_push_back(const DATE& rItem, MeetingDates& rItems){COleDateTime datNotAvailable(rItem);DWORD dwDatNotAvailable = EncodeMeetingDate(0, datNotAvailable);rItems[dwDatNotAvailable] = datNotAvailable;}

我像这样调整了我的调用代码:

theApp.MSAToolsInterface().ConvertSAFEARRAY(psaDates, mapMeetingDates);

但是当我编译这个时,我现在得到一个错误:

<块引用>

5>PublishersDatabaseDlg.obj : error LNK2001: 未解析的外部符号public: static void __cdecl CMSATools::ConvertSAFEARRAY>>>(struct tagSAFEARRAY *,class std::map> > &)"(??$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)

我做错了什么?


到目前为止,当我进行 DATE... 模板化调用时,我的代码无法编译:

templatevoid CMSATools::to_clear(to& rItems){rItems.clear();}模板void CMSATools::to_push_back(const from& rItem, to& rItems){rItems.push_back(rItem);}模板<>void CMSATools::to_clear(CStringArray& rItems){rItems.RemoveAll();}模板<>void CMSATools::to_push_back(const BSTR& rItem, CStringArray& rItems){rItems.Add(rItem);}模板<>void CMSATools::to_push_back(const DATE& rItem, MeetingDates& rItems){COleDateTime datNotAvailable(rItem);DWORD dwDatNotAvailable = EncodeMeetingDate(0, datNotAvailable);rItems[dwDatNotAvailable] = datNotAvailable;}模板void CMSATools::ConvertSAFEARRAY(SAFEARRAY* psaItems, to& rItems){from* pVals = nullptr;HRESULT hr = SafeArrayAccessData(psaItems, (void**)&pVals);//直接访问SA内存如果(成功(小时)){长下界,上界;//获取数组边界hr = SafeArrayGetLBound(psaItems, 1, &lowerBound);如果(失败(小时))抛出_com_error(hr);hr = SafeArrayGetUBound(psaItems, 1, &upperBound);如果(失败(小时))抛出_com_error(hr);to_clear(rItems);long cnt_elements = upperBound -lowerBound + 1;for (int i = 0; i < cnt_elements; ++i)//遍历返回值{to_push_back<from, to>(pVals[i], rItems);}hr = SafeArrayUnaccessData(psaItems);如果(失败(小时))抛出_com_error(hr);}别的{抛出_com_error(hr);}hr = SafeArrayDestroy(psaItems);如果(失败(小时))抛出_com_error(hr);}


我这是对类似标题问题的回答:

将 std::map 作为模板模板参数传递时出错

而且我认为它可能适用于我的情况,但我不确定如何实现它.如果确实是这个原因.


我的头类中有这个片段:

<预><代码>模板静态无效 to_clear(to& rItems);模板static void to_push_back(const from& rItem, to& rItems);模板<>static void to_clear(CStringArray& rItems);模板<>static void to_push_back(const BSTR& rItem, CStringArray& rItems);模板<>static void to_push_back(const DATE& rItem, MeetingDates& rItems);模板static void ConvertSAFEARRAY(SAFEARRAY* psaItems, to& rItems);静态 DWORD EncodeMeetingDate(int iMeetingType, COleDateTime datMeeting);

在头文件的顶部,我有:

#pragma once#include "DemoPickerDlg.h";#include <地图>#include <向量>#ifdef _WIN64#import "..\\..\\MSAToolsLibrary\\MSAToolsLibrary\\bin\\x64\\Release\\MSAToolsLibrary.tlb";raw_interfaces_only named_guids#别的#import "..\\..\\MSAToolsLibrary\\MSAToolsLibrary\\bin\\x86\\Release\\MSAToolsLibrary.tlb";raw_interfaces_only named_guids#万一使用 MeetingDates = std::map;使用 ListDiscussionItems = std::list;使用 ListStudentItems = std::list;使用 ListDutyHistoryLookupItems = std::list;

解决方案

有一个链接问题(为什么模板只能在头文件?)在评论中提供给我.但答案本身并没有让我清楚.它链接到的文章帮助我理解:

引用:

<块引用>

但是为了理解为什么事情是这样的,首先要接受以下事实:

  1. 模板不是类或函数.模板是编译器用来生成一系列类或函数的模式".

这让我很清楚.我将模式代码移动到标题中,现在可以正常编译.我发现这是最简单的解决方法.

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:

  1. Can these methods that convert safe arrays into std::list objects be turned into a template function?
  2. 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>;

解决方案

There is a linked question (Why can templates only be implemented in the header file?) provided to me in the comments. But the answer itself didn't make it clear for me. It was the article that it linked to that helped me understand:

To quote:

But in order to understand why things are the way they are, first accept these facts:

  1. A template is not a class or a function. A template is a "pattern" that the compiler uses to generate a family of classes or functions.

That is what made it clear to me. I moved mode code into the header and it now compiles fine. I found that the easiest resolution.

这篇关于我试图向我的班级添加一个新的模板辅助函数,但现在出现 LNK2001 错误.怎么修?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆