[英]Compiling hybrid classes (templated and untemplated functions) into a static library
为了科学,我正在编写一个游戏引擎库。 我过去曾成功编写过 static 库,尽管没有模板函数。
在处理模板化函数时,我习惯将它们的代码与非模板化的代码分开。 模板函数代码位于 header 文件中,而其他的位于 .cpp/.hpp 文件中。
下面是其中一个模块的片段:信号。
// Connection.h
#pragma once
#include <memory>
#include <functional>
namespace mqs
{
using Disconnector = std::function<void(std::uint32_t)>;
class Connection final
{
public:
explicit Connection(std::shared_ptr<mqs::Disconnector> disconnector, std::uint32_t index);
bool connected() const;
void disconnect() const;
private:
std::uint32_t index;
std::weak_ptr<mqs::Disconnector> disconnector;
};
}
// Signal.h
#pragma once
#include <vector>
#include "connection.hpp"
namespace mqs
{
template <typename...>
class Signal;
template <typename R, typename... A>
class Signal<R(A...)> final
{
public:
Signal();
template <typename Lambda>
mqs::Connection connect(Lambda&& lambda) {
slots.push_back(std::forward<Lambda>(lambda));
return mqs::Connection(disconnector, slots.size() - 1U);
}
void operator()(A&&... args) const;
unsigned connections() const;
private:
std::vector<std::function<R(A...)>> slots;
std::shared_ptr<mqs::Disconnector> disconnector;
};
}
// Connection.hpp
#pragma once
#include "connection.h"
namespace mqs
{
Connection::Connection(std::shared_ptr<mqs::Disconnector> disconnector, std::uint32_t index) {
this->index = index;
this->disconnector = disconnector;
}
bool Connection::connected() const {
return !disconnector.expired();
}
void Connection::disconnect() const {
if (const auto& lock = disconnector.lock()) {
lock->operator()(index);
}
}
}
// Signal.hpp
#pragma once
#include "signal.h"
namespace mqs
{
template <typename R, typename... A>
Signal<R(A...)>::Signal() {
disconnector = std::make_shared<mqs::Disconnector>([this](std::uint32_t index) {
slots.erase(slots.begin() + index);
});
}
template <typename R, typename... A>
void Signal<R(A...)>::operator()(A&&... args) const {
for (auto& slot : slots) {
slot(std::forward<A>(args)...);
}
}
template <typename R, typename... A>
unsigned Signal<R(A...)>::connections() const {
return slots.size();
}
}
它可以编译,但是我一直在处理的问题之一是mqs::Signal
(signal.hpp) 不能包含在不同的头文件中,否则会导致function already has a body
。 包含signal.h
时,我得到unresolved external symbol
,这是有道理的。
我也尝试过inline
上面他们的.hpp 文件中定义的所有函数。
除了使用巨大的仅标头方法之外,还有什么方法可以实现这一点?
正如您已经知道的那样,您需要将 function 模板inline
。 这是必要的,因为模板首先需要被实例化为可编译的函数,这意味着编译器需要源代码。
但是,如果您查看诸如Signal<R(A...)>::disconnector;
这样的成员。 ,您会注意到它们不依赖于R
或A...
。 因此,您可以将它们移动到非模板基础 class。
对于仍然需要包含的实现文件,例如因为它们包含模板代码,有一个相当普遍的约定使用扩展名.ipp
。 这些通常包含在相应的.hpp
文件中,就在 header 防护的#endif
之前。 因此.ipp
文件不需要自己的 header 保护。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.