我正在用C ++实现一种事件机制(类似于C#中的事件)。我为此使用模板类。 当我尝试创建事件时,发生链接错误
ERROR:LNK2019 unresolved external symbol
"public: __cdecl NS::Event<void __cdecl(class std::basic_string<char,struct std::char_traits<char>,
class std::allocator<char> >)>
我的C ++代码如下所示。
'''EventManager.CPP
#include "EventManager.h"
using namespace NS;
template <class RetType, class... Args > struct Event<RetType(Args ...)> ::ComparableClosure
{
Closure Callable;
void* Object;
uint8_t* Functor;
int FunctorSize;
ComparableClosure(const ComparableClosure&) = delete;
ComparableClosure() : Object(nullptr), Functor(nullptr), FunctorSize(0) { }
ComparableClosure(Closure&& closure) : Callable(std::move(closure)), Object(nullptr), Functor(nullptr), FunctorSize(0) { }
~ComparableClosure()
{
if (Functor != nullptr)
delete[] Functor;
}
ComparableClosure& operator=(const ComparableClosure& closure)
{
Callable = closure.Callable;
Object = closure.Object;
FunctorSize = closure.FunctorSize;
if (closure.FunctorSize == 0)
{
Functor = nullptr;
}
else
{
Functor = new uint8_t[closure.FunctorSize];
std::memcpy(Functor, closure.Functor, closure.FunctorSize);
}
return *this;
}
bool operator==(const ComparableClosure& closure)
{
if (Object == nullptr && closure.Object == nullptr)
{
return Callable.target_type() == closure.Callable.target_type();
}
else
{
return Object == closure.Object && FunctorSize == closure.FunctorSize
&& std::memcmp(Functor, closure.Functor, FunctorSize) == 0;
}
}
};
template <class RetType, class... Args > struct Event<RetType(Args ...)> ::ClosureList
{
ComparableClosure* Closures;
int Count;
ClosureList(ComparableClosure* closures, int count)
{
Closures = closures;
Count = count;
}
~ClosureList()
{
delete[] Closures;
}
};
template <class RetType, class... Args > bool Event<RetType(Args ...)> ::addClosure(const ComparableClosure& closure)
{
auto events = std::atomic_load(&m_events);
int count;
ComparableClosure* closures;
if (events == nullptr)
{
count = 0;
closures = nullptr;
}
else
{
count = events->Count;
closures = events->Closures;
}
auto newCount = count + 1;
auto newClosures = new ComparableClosure[newCount];
if (count != 0)
{
for (int i = 0; i < count; i++)
newClosures[i] = closures[i];
}
newClosures[count] = closure;
auto newEvents = ClosureListPtr(new ClosureList(newClosures, newCount));
if (std::atomic_compare_exchange_weak(&m_events, &events, newEvents))
return true;
return false;
}
template <class RetType, class... Args > bool Event<RetType(Args ...)> ::removeClosure(const ComparableClosure& closure)
{
auto events = std::atomic_load(&m_events);
if (events == nullptr)
return true;
int index = -1;
auto count = events->Count;
auto closures = events->Closures;
for (int i = 0; i < count; i++)
{
if (closures[i] == closure)
{
index = i;
break;
}
}
if (index == -1)
return true;
auto newCount = count - 1;
ClosureListPtr newEvents;
if (newCount == 0)
{
newEvents = nullptr;
}
else
{
auto newClosures = new ComparableClosure[newCount];
for (int i = 0; i < index; i++)
newClosures[i] = closures[i];
for (int i = index + 1; i < count; i++)
newClosures[i - 1] = closures[i];
newEvents = ClosureListPtr(new ClosureList(newClosures, newCount));
}
if (std::atomic_compare_exchange_weak(&m_events, &events, newEvents))
return true;
return false;
}
template <class RetType, class... Args > Event<RetType(Args ...)>::Event()
{
std::atomic_store(&m_events, ClosureListPtr());
}
template <class RetType, class... Args > Event<RetType(Args ...)>::Event(const Event& event)
{
std::atomic_store(&m_events, std::atomic_load(&event.m_events));
}
template <class RetType, class... Args > Event<RetType(Args ...)>::~Event()
{
(*this) = nullptr;
}
template <class RetType, class... Args > void Event<RetType(Args ...)> ::operator -=(Closure f)
{
ComparableClosure closure(std::move(f));
while (true)
{
if (removeClosure(closure))
break;
}
}
template <class RetType, class... Args > void Event<RetType(Args ...)> ::operator +=(Closure f)
{
ComparableClosure closure(std::move(f));
while (true)
{
if (addClosure(closure))
break;
}
}
template <class RetType, class... Args > bool Event<RetType(Args ...)> ::operator==(nullptr_t nullpointer)
{
auto events = std::atomic_load(&m_events);
return events == nullptr;
}
template <class RetType, class... Args > bool Event<RetType(Args ...)> ::operator!=(nullptr_t nullpointer)
{
auto events = std::atomic_load(&m_events);
return events != nullptr;
}
template <class RetType, class... Args > void Event<RetType(Args ...)> ::operator=(nullptr_t nullpointer)
{
while (true)
{
auto events = std::atomic_load(&m_events);
if (!std::atomic_compare_exchange_weak(&m_events, &events, ClosureListPtr()))
continue;
break;
}
}
template <class RetType, class... Args > void Event<RetType(Args ...)> ::operator =(const Event& event)
{
std::atomic_store(&m_events, std::atomic_load(&event.m_events));
}
template <class RetType, class... Args > template <typename TObject> void Event<RetType(Args ...)> ::Bind(RetType(TObject::* function)(Args...), TObject* object)
{
ComparableClosure closure;
closure.Callable = [object, function](Args&&...args)
{
return (object->*function)(std::forward<Args>(args)...);
};
closure.FunctorSize = sizeof(function);
closure.Functor = new uint8_t[closure.FunctorSize];
std::memcpy(closure.Functor, (void*)&function, sizeof(function));
closure.Object = object;
while (true)
{
if (addClosure(closure))
break;
}
}
template <class RetType, class... Args > template <typename TObject> void Event<RetType(Args ...)> ::Unbind(RetType(TObject::* function)(Args...), TObject* object)
{
ComparableClosure closure;
closure.FunctorSize = sizeof(function);
closure.Functor = new uint8_t[closure.FunctorSize];
std::memcpy(closure.Functor, (void*)&function, sizeof(function));
closure.Object = object;
while (true)
{
if (removeClosure(closure))
break;
}
}
template <class RetType, class... Args > void Event<RetType(Args ...)> ::operator()()
{
auto events = std::atomic_load(&m_events);
if (events == nullptr)
return;
auto count = events->Count;
auto closures = events->Closures;
for (int i = 0; i < count; i++)
closures[i].Callable();
}
template <class RetType, class... Args > template <typename TArg0, typename ...Args2> void Event<RetType(Args ...)> ::operator()(TArg0 a1, Args2... tail)
{
auto events = std::atomic_load(&m_events);
if (events == nullptr)
return;
auto count = events->Count;
auto closures = events->Closures;
for (int i = 0; i < count; i++)
closures[i].Callable(a1, tail...);
}
'''
'''EventManager.h
#pragma once
#include <typeinfo>
#include <functional>
#include <stdexcept>
#include <memory>
#include <atomic>
namespace NS
{
template <typename TFunc> class __declspec(dllexport) Event;
template <class RetType, class... Args> class __declspec(dllexport) Event<RetType(Args ...)> final
{
private:
typedef typename std::function<RetType(Args ...)> Closure;
struct ComparableClosure;
struct ClosureList;
typedef std::shared_ptr<ClosureList> ClosureListPtr;
private:
ClosureListPtr m_events;
private:
bool addClosure(const ComparableClosure& closure);
bool removeClosure(const ComparableClosure& closure);
public:
Event();
Event(const Event& event);
~Event();
void operator =(const Event& event);
void operator=(nullptr_t nullpointer);
bool operator==(nullptr_t nullpointer);
bool operator!=(nullptr_t nullpointer);
void operator +=(Closure f);
void operator -=(Closure f);
template <typename TObject>
void Bind(RetType(TObject::* function)(Args...), TObject* object);
template <typename TObject>
void Unbind(RetType(TObject::* function)(Args...), TObject* object);
void operator()();
template <typename TArg0, typename ...Args2>
void operator()(TArg0 a1, Args2... tail);
};
'''
我试图从另一个类实例化Event,如下所示。但是它在构建过程中显示错误。
如果我评论以下行,我可以毫无错误地进行构建。
'''
Event <void(string)> LogNotification;
'''
另外,如果我将代码放在EventManager.h和EventManager.cpp中的单个EventManager.h文件中,它将起作用。但这不符合我的要求。我需要将标头和cpp文件分开以隐藏代码。