【问题标题】:Linker Error - Not sure what it is not linking链接器错误 - 不确定它没有链接什么
【发布时间】:2019-02-13 13:42:46
【问题描述】:

我一直试图找出我的代码中未正确链接或声明的内容。我正在用 C++ 编写一个简单的游戏引擎以用于学习目的,并且正在尝试创建一个状态机。链接器错误与 unordered_list、list 或 map 有关。我不确定是哪个。错误是针对具有两个参数的构造函数,它们是两个 typedef,并且包含在我显示的代码中,当我调用该构造函数时会发生错误。

IState.h

#ifndef ZX_STATE_H
#define ZX_STATE_H

#include "coreDefines.h"
#include "zxstring.h"
ZX_NS_START

class IState
{
    tstring pm_name;
public:
    const tstring& name();
    virtual ~IState() = default;
    virtual void Pre() = 0;
    virtual void Run() = 0;
    virtual void Post() = 0;
};

ZX_NS_END
#endif

IStateMachine.h

#ifndef ZX_ISTATEMACHINE_H
#define ZX_ISTATEMACHINE_H
#include "object.h"
#include "zxstring.h"
#include "IState.h"
#include <unordered_set>
#include <map>
#include <list>

ZX_NS_START
typedef std::map<tstring, IState*> StateMap;
typedef std::unordered_set<tstring> StateSet;
typedef std::list<StateSet> RunOrder;
class IStateMachine : object, IState
{
public:
    const tstring defaultState = T("zx default state");

    IStateMachine();
    IStateMachine(RunOrder** runOrder, StateSet** states);
    virtual ~IStateMachine();
    void Add(IState* state);
    void Remove(IState* state);

private:
    StateMap pm_states;
    RunOrder** pm_runOrder;
    StateSet** pm_activeStates;

    void Pre() override;
    void Run() override;
    void Post() override;

    void SetUpDefaultState();
    class DefaultState: IState
    {
        IStateMachine* pm_parent;
    public:
        DefaultState();
        explicit DefaultState(IStateMachine* parent);
        void Pre() override;
        void Run() override;
        void Post() override;
    };
};

ZX_NS_END
#endif

IStateMachine.cpp

#include "IStateMachine.h"
USINGZX;

IStateMachine::IStateMachine(): pm_states(StateMap()), pm_runOrder(nullptr), pm_activeStates(nullptr)
{
    SetUpDefaultState();
}

IStateMachine::IStateMachine(RunOrder** runOrder, StateSet** states) : pm_states(StateMap()), pm_runOrder(runOrder), pm_activeStates(states)
{
    SetUpDefaultState();
}

IStateMachine::~IStateMachine()
{
    delete pm_states[defaultState];
}


void IStateMachine::Add(IState* state)
{
    pm_states.insert(std::make_pair(state->name(), state));
}

void IStateMachine::Remove(IState* state)
{
    pm_states.erase(state->name());
}


void IStateMachine::Pre()
{
    pm_states[defaultState]->Pre();
}

void IStateMachine::Run()
{
    pm_states[defaultState]->Run();
}

void IStateMachine::Post()
{
    pm_states[defaultState]->Post();
}

void IStateMachine::SetUpDefaultState()
{
    DefaultState* def = new DefaultState(this);
    pm_states.insert(std::make_pair(defaultState, (IState*)def));
}

IStateMachine::DefaultState::DefaultState() :pm_parent(nullptr)
{
}

IStateMachine::DefaultState::DefaultState(IStateMachine* parent): pm_parent(parent)
{
}

void IStateMachine::DefaultState::Pre()
{
    for(const auto& states : **pm_parent->pm_runOrder)
    {
        for(const auto& runState : states)
        {
            pm_parent->pm_states[runState]->Pre();
        }
    }
}

void IStateMachine::DefaultState::Run()
{
    for(const auto& states: **pm_parent->pm_runOrder)
    {
        for(const auto& runState : states)
        {
            pm_parent->pm_states[runState]->Run();
        }
    }
}

void IStateMachine::DefaultState::Post()
{
    for (const auto& states : **pm_parent->pm_runOrder)
    {
        for (const auto& runState : states)
        {
            pm_parent->pm_states[runState]->Post();
        }
    }
}

这是长长的错误信息

错误 LNK2019 未解析的外部符号“public: __thiscall Zx::IStateMachine::IStateMachine(class std::list,class std::allocator >,struct std::hash,class std::allocator > >,struct std: :equal_to,class std::allocator > >,class std::allocator,class std::allocator > > >,class std::allocator,class std::allocator >,struct std::hash,class std::allocator > >,struct std::equal_to,class std::allocator > >,class std::allocator,class std::allocator > > > > > * *,class std::unordered_set,class std::allocator >,struct std::hash,class std::allocator > >,struct std::equal_to,class std::allocator > >,class std::allocator,class std::allocator > > > * *)" (??0IStateMachine@ Zx@@QAE@PAPAV?$list@V?$unordered_set@V?$basic_string@_WU?$char_traits@_W@std@@V?$allocator@_W@2@@std@@U?$hash@V? $basic_string@_WU?$char_traits@_W@std@@V?$allocator@_W@2@@std@@@2@U?$equal_to@V?$basic_string@_WU?$char_traits@_W@std@@V ?$allocator@_W@2@@std@@@2@V?$allocator@V?$basic_string@_WU?$char_traits@_W@std@@V?$allocator@_W@2@ @std@@@2@@std@@V?$allocator@V?$unordered_set@V?$basic_string@_WU?$char_traits@_W@std@@V?$allocator@_W@2@@std@@U ?$hash@V?$basic_string@_WU?$char_traits@_W@std@@V?$allocator@_W@2@@std@@@2@U?$equal_to@V?$basic_string@_WU?$char_traits@ _W@std@@V?$allocator@_W@2@@std@@@2@V?$allocator@V?$basic_string@_WU?$char_traits@_W@std@@V?$allocator@_W@2@ @std@@@2@@std@@@2@@std@@PAPAV?$unordered_set@V?$basic_string@_WU?$char_traits@_W@std@@V?$allocator@_W@2@@std@ @U?$hash@V?$basic_string@_WU?$char_traits@_W@std@@V?$allocator@_W@2@@std@@@2@U?$equal_to@V?$basic_string@_WU?$ char_traits@_W@std@@V?$allocator@_W@2@@std@@@2@V?$allocator@V?$basic_string@_WU?$char_traits@_W@std@@V?$allocator@_W@ 2@@std@@@2@@3@@Z) 在函数“public: __thiscall TestStateMachine::TestStateMachine(class std::list,class std::allocator >,struct std::hash,class std::分配器 > >,struct std::equal_to,class std::allocator > >,class std::allocator,class std::allocator > > >,class std::allocator,class std::allocator >,struct std: :hash,class std::allocator > >,struct std::equal_to,class std::allocator > >,class std::allocator,class std::allocator > > > > > * *,class std::unordered_set,类 std::allocator >,struct std::hash,类 std::allocator > >,struct std::equal_to,类 std::allocator > >,类 std::allocator,类 std::allocator > > > * *)" (??0TestStateMachine@@QAE@PAPAV?$list@V?$unordered_set@V?$basic_string@_WU?$char_traits@_W@std@@V?$allocator@_W@2@@std@@U ?$hash@V?$basic_string@_WU?$char_traits@_W@std@@V?$allocator@_W@2@@std@@@2@U?$equal_to@V?$basic_string@_WU?$char_traits@ _W@std@@V?$allocator@_W@2@@std@@@2@V?$allocator@V?$basic_string@_WU?$char_traits@_W@std@@V?$allocator@_W@2@ @std@@@2@@std@@V?$allocator@V?$unordered_set@V?$basic_string@_WU?$char_traits@_W@std@@V?$allocator@_W@2@@std@@U ?$hash@V?$basic_string@_WU?$char_traits@_W@std@@V?$allocator@_W@2@@std@@@2@U?$equal_to@V?$basic_string@_WU?$char_traits@ _W@std@@V?$allocator@_W@2@@std@@@2@V?$allocator@V?$basic_string@_WU?$char_traits@_W@std@@V?$alloca tor@_W@2@@std@@@2@@std@@@2@@std@@PAPAV?$unordered_set@V?$basic_string@_WU?$char_traits@_W@std@@V?$allocator@_W @2@@std@@U?$hash@V?$basic_string@_WU?$char_traits@_W@std@@V?$allocator@_W@2@@std@@@2@U?$equal_to@V? $basic_string@_WU?$char_traits@_W@std@@V?$allocator@_W@2@@std@@@2@V?$allocator@V?$basic_string@_WU?$char_traits@_W@std@@V ?$allocator@_W@2@@std@@@2@@2@@Z)

我通常可以很容易地解决这些问题,但不管出于什么原因,这个问题让我感到困惑。(可能与错误消息中不可读的类型有关)

我不相信这会产生任何后果,但是,这里是调用链接器错误的测试代码

StateMachineTest.cpp

class TestStateMachine : zx IStateMachine
{
public:
    TestStateMachine(zx RunOrder** order, zx StateSet** active) : zx IStateMachine(order, active)
    {

    }
};

TEST_CLASS(StateMachineTest)
{
public:
    TEST_METHOD(IStateMachineTest)
    {
        auto* order = new zx RunOrder();
        auto* active = new zx StateSet();



        TestStateMachine test = TestStateMachine(&order, &active);
    }

};

【问题讨论】:

  • 看起来IStateMachine.cpp 不包含在您的构建中。
  • 你是怎么编译的/编译命令是什么?
  • 另一种可能性:IStateMachine.h 有条件地将类放入命名空间zx,显然是基于一些宏。但StateMachineTest.cpp 无条件引用zx::IStateMachine。难道是两个源文件编译的条件不同,导致一个源认为该类在命名空间zx,而另一个认为该类在全局命名空间中?
  • 我刚刚使用在 IStateMachine.h 中定义并在 IStateMachine.cpp 中声明的静态变量对其进行了测试,不幸的是,事实并非如此,因为它可以很好地链接该变量。
  • zx 是用于轻松更改命名空间名称的简写,它没有任何条件做任何事情,我只是觉得它看起来更好,而且只是在玩宏,哈哈。

标签: c++ linker linker-errors


【解决方案1】:

我删除了你所有的宏内容,以及缺少头文件的 #includes,提供了 tstring 的替代品,如 typedef std::basic_string&lt;TCHAR&gt; tstring;const tstring&amp; IState::name() { return pm_name; } 的实现,并且代码编译没有错误。

【讨论】:

  • 对于任何想知道的人来说,问题出在 tstring 宏上,由于 typedef std::unordered_set StateSet 中的某些原因,它会导致链接器针对该类型抛出错误,即使 tstring 会编译下来到 std::string,如果被替换,它将编译得很好。
  • 请避免使用宏时带来的麻烦。例如。 “zx 是轻松更改命名空间名称的简写”,可以通过 namespace foo = bar; 轻松实现。
  • 实际上需要 tstring 宏,它允许多字节和 Unicode 编码。但我知道我不应该玩宏,但这就是我学习的方式,玩火并弄清楚后果哈哈。
  • @JoeMccane 我猜你在 Windows 上? #include &lt;tchar.h&gt; 并使用我的回答中的 typedef。
【解决方案2】:

假设USINGZXusing namespace zx;,那么这段代码没有在zx 命名空间中定义IStateMachine::IStateMachine,而是在全局命名空间中。

USINGZX;

IStateMachine::IStateMachine(): pm_states(StateMap()), pm_runOrder(nullptr), pm_activeStates(nullptr)
{
    SetUpDefaultState();
}

如果您想在 zx 命名空间中定义 IStateMachine::IStateMachine,那么您必须说

zx::IStateMachine::IStateMachine(): pm_states(StateMap()), pm_runOrder(nullptr), pm_activeStates(nullptr)
{
    SetUpDefaultState();
}

namespace zx {

IStateMachine::IStateMachine(): pm_states(StateMap()), pm_runOrder(nullptr), pm_activeStates(nullptr)
{
    SetUpDefaultState();
}

}

【讨论】:

  • 我尝试了修复,不幸的是这不是问题所在。无论如何,声明不需要在命名空间中声明,只有在定义时才需要。当我把 using namespace Zx;在调用或引用变量/函数时,它就像您在命名空间内一样,但在定义它们时并非如此。感谢您的帮助!
  • 我也知道情况并非如此,因为我有其他类的设置方式相同,没有问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-11-11
  • 1970-01-01
  • 2021-06-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多