c ++错误LNK1120:在静态函数内部调用时有1个未解析的外部

时间:2016-12-03 10:31:49

标签: c++

我在静态方法中调用模板函数时遇到问题。 在这里我的代码: baseEvent.h

dom-if

和baseEvent.cpp

#ifndef BASE_EVENT_H
#define BASE_EVENT_H

#include <unordered_map>
#include <functional>

class baseEvent
{
public:
    template<typename Sender,typename EventArgs>
    using pureEvent = std::function<void(Sender, EventArgs)>;
    template<typename pureEvent>
    using eventMap = std::unordered_map<int, pureEvent>;

    template<typename Sender, typename EventArgs>
    struct Event
    {
        int AddEvent(pureEvent<Sender, EventArgs>);
        void RemoveEvent(int);
        void LaunchEvents(Sender, EventArgs);
    private:
        eventMap<pureEvent<Sender,EventArgs>> Events;
    };
};

#endif

anotherClass.h

    #include "baseEvent.h"




template <typename Sender, typename EventArgs>
int baseEvent::Event<Sender, EventArgs>::AddEvent(pureEvent<Sender, EventArgs> pure_event)
{
    auto uniqeID = 0;
    if (Events.rbegin() != Events.rend())
        uniqeID = Events.rbegin()->first + 1;
    Events.insert(std::make_pair(uniqeID, pure_event));
    return uniqeID;
}

template <typename Sender, typename EventArgs>
void baseEvent::Event<Sender, EventArgs>::RemoveEvent(int uniqeID)
{
    auto it = Events.find(uniqeID);
    if (it != Events.end())
        Events.erase(it);
}

template <typename Sender, typename EventArgs>
void baseEvent::Event<Sender, EventArgs>::LaunchEvents(Sender sender, EventArgs e)
{
    if (Events.empty())return;
    for (auto& singleEvent : Events)
    {
        singleEvent(sender, e);
    }
}

anotherClass.cpp

    #include "baseEvent.h"
class anotherClass
{
public:
    typedef baseEvent::pureEvent<nullptr_t, int> ballEvent;

    static void Update();

    static int AddOnChangeOwnerEvent(ballEvent);
    static void RemoveOnChangeOwnerEvent(int);
    static void LaunchOnChangeOwnerEvents(int);
private:
    static baseEvent::Event<nullptr_t, int> OnChangeOwnerEvents;
};

它给了我这个错误:

  

错误2错误LNK2019:未解析的外部符号&#34; public:void   __thiscall baseEvent :: Event :: LaunchEvents(std :: nullptr_t,int)&#34;   (?LaunchEvents @?$ Event @ $$ TH @ baseEvent @@ QAEX $$ TH @ Z)引用于   function&#34; public:static void __cdecl   anotherClass :: LaunchOnChangeOwnerEvents(INT)&#34;   (?LaunchOnChangeOwnerEvents @ ball @@ SAXH @ Z)E:\ projects \ ProFCEngine \ SoccerAI \ anotherClass.obj SoccerAI

它应该可以正常工作,我做错了什么?

更新

如果我使用模板struct baseEvent :: Event; LaunchOnChangeOwnerEvents将修复,但如果我在我的主要执行此操作,我会再次收到错误。

#include "anotherClass.h"

baseEvent::Event< nullptr_t, int> ball::OnChangeOwnerEvents;

void ball::Update()
{
    LaunchOnChangeOwnerEvents(0);
    //.
    //.
    //.
}

inline int anotherClass::AddOnChangeOwnerEvent(ballEvent ball_event)
{
    return OnChangeOwnerEvents.AddEvent(ball_event);
}

inline void anotherClass::RemoveOnChangeOwnerEvent(int uniqeID)
{
    return OnChangeOwnerEvents.RemoveEvent(uniqeID);
}

inline void anotherClass::LaunchOnChangeOwnerEvents(int event_args)
{
    return OnChangeOwnerEvents.LaunchEvents(nullptr, event_args);
}

2 个答案:

答案 0 :(得分:1)

使用模板类,您不能只将实现放在源文件中。源文件不知道将调用函数的模板参数,因此它不会生成任何已编译的函数。因此,您会收到一个链接器错误,该函数未解析。

您可以通过将实现移动到标题中来修复此问题,并与类定义内联。

答案 1 :(得分:0)

太长没看过

最简单的解决方案是在baseEvent.cpp

的末尾添加以下行
template struct baseEvent::Event<nullptr_t, int>;

<强>答案

让我们假设你的主要是这样的:

 #include "anotherClass.h"

 int main()
 {
         anotherClass c;

         c.Update();

         return 0;
  }

当我们编译main.cpp

 g++ -std=c++11 -c main.cpp -o main.o

并检查我们的翻译单位需要/提供的符号:

 $nm -gC main.o
 0000000000000000 T main
                  U anotherClass::Update()

main.cpp需要anotherClass::Update的实施。

让我们编译anotherClass.cpp

 g++ -std=c++11 -c anotherClass.cpp -o anotherClass.o

再次检查我们的翻译单位需要/提供的符号:

$nm -gC anotherClass.o
[...]
0000000000000000 T anotherClass::Update()
                 U baseEvent::Event<decltype(nullptr), int>::LaunchEvents(decltype(nullptr), int)
[...]

anotherClass.cpp提供了很多符号,为了清晰起见我删除了它们。正如您在anotherClass.cpp编译期间所看到的那样,nullptr_t, int的LaunchEvents未编译,因为编译器没有定义。

当我们检查baseEvent.onm的内容时,我们会了解到它没有提供任何符号,也不需要任何符号。

nm -gC baseEvent.o

正如我之前所写,问题是anotherClass.cpp只声明LaunchEvents而不是定义。

明确的实例化

第一种方法是强制在baseEvent.cpp

中实例化此模板
template struct baseEvent::Event<nullptr_t, int>;

如果我们在此类更改后检查baseEvent.o,我们会在此翻译单元中看到所需的符号:

$nm -gC baseEvent.o
[...]
0000000000000000 W baseEvent::Event<decltype(nullptr), int>::RemoveEvent(int)
0000000000000000 W baseEvent::Event<decltype(nullptr), int>::LaunchEvents(decltype(nullptr), int)
0000000000000000 W baseEvent::Event<decltype(nullptr), int>::LaunchEvents(baseEvent::Event<decltype(nullptr), int>, int)
0000000000000000 W baseEvent::Event<decltype(nullptr), int>::AddEvent(std::function<void (decltype(nullptr), int)>)
0000000000000000 W baseEvent::Event<decltype(nullptr), int>::AddEvent(std::function<void (baseEvent::Event<decltype(nullptr), int>, int)>)
[...]

将模板定义移至标题

正如@qxz在他/她的回答中所说,你可以将模板实现移到标题中。您可以在课后添加内联函数

#ifndef BASE_EVENT_H
#define BASE_EVENT_H

#include <unordered_map>
#include <functional>

class baseEvent
{
public:
[...]

    template<typename Sender, typename EventArgs>
    struct Event
    {
        int AddEvent(pureEvent<Sender, EventArgs>);
        void RemoveEvent(int);
        void LaunchEvents(Sender, EventArgs);
    private:
        eventMap<pureEvent<Sender,EventArgs>> Events;
    };
};

[...]

template <typename Sender, typename EventArgs>
inline void baseEvent::Event<Sender, EventArgs>::LaunchEvents(Sender sender, EventArgs e)
{
    if (Events.empty())return;
    for (auto& singleEvent : Events)
    {
        singleEvent.second(sender, e);
    }
}

#endif

或者在类定义

中添加实现
class baseEvent
{
public:
    [...]

    template<typename Sender, typename EventArgs>
    struct Event
    {
        [...]
        void LaunchEvents(Sender sender, EventArgs e)
        {
                if (Events.empty())return;

                for (auto& singleEvent : Events)
                {
                    singleEvent.second(sender, e);
                }
        }
    private:
        eventMap<pureEvent<Sender,EventArgs>> Events;
    };
};

如果您这样做,将在anotherClass.o

中提供实施
$ nm -gC anotherClass.o  | grep LaunchEvent
0000000000000000 W baseEvent::Event<decltype(nullptr), int>::LaunchEvents(decltype(nullptr), int)
0000000000000000 W baseEvent::Event<decltype(nullptr), int>::LaunchEvents(baseEvent::Event<decltype(nullptr), int>, int)