繁体   English   中英

将混合类(模板化和非模板化函数)编译到 static 库中

[英]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;这样的成员。 ,您会注意到它们不依赖于RA... 因此,您可以将它们移动到非模板基础 class。

对于仍然需要包含的实现文件,例如因为它们包含模板代码,有一个相当普遍的约定使用扩展名.ipp 这些通常包含在相应的.hpp文件中,就在 header 防护的#endif之前。 因此.ipp文件不需要自己的 header 保护。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM