gpt4 book ai didi

c++ - 在单独的库中使用 CRTP 进行静态成员初始化

转载 作者:行者123 更新时间:2023-11-30 01:21:32 24 4
gpt4 key购买 nike

在浏览网页后,我发现了一些关于利用 CRTP 允许在运行时实例化静态成员的强大模式的引用资料:

C++: Compiling unused classes

Initialization class for other classes - C++

等等。所提出的方法效果很好,除非将此类层次结构放入外部库中。这样做,运行时初始化不再起作用,除非我在派生类的头文件中手动#include 某处。但是,这违背了我的主要目的 - 无需更改其他源文件即可将新命令添加到我的应用程序。

一些代码,希望对你有帮助:

class CAction
{
protected:
// some non relevant stuff
public:
// some other public API
CAction(void) {}
virtual ~CAction(void) {}

virtual std::wstring Name() const = 0;
};

template <class TAction>
class CCRTPAction : public CAction
{
public:
static bool m_bForceRegistration;
CCRTPAction(void) { m_bForceRegistration; }
~CCRTPAction(void) { }

static bool init() {
CActionManager::Instance()->Add(std::shared_ptr<CAction>(new TAction));
return true;
}
};

template<class TAction> bool CCRTPAction<TAction>::m_bForceRegistration = CCRTPAction<TAction>::init();

以这种方式完成的实现:

class CDummyAction : public CCRTPAction<CDummyAction>
{
public:
CDummyAction() { }
~CDummyAction() { }
std::wstring Name() const { return L"Dummy"; }
};

最后,这里是容器类 API:

class CActionManager
{
private:
CActionManager(void);
~CActionManager(void);
std::vector<std::shared_ptr<CAction>> m_vActions;
static CActionManager* instance;
public:
void Add(std::shared_ptr<CAction>& Action);
const std::vector<std::shared_ptr<CAction>>& AvailableActions() const;
static CActionManager* Instance() {
if (nullptr == instance) {
instance = new CActionManager();
}
return instance;
}
};

在单个项目解决方案中一切正常。但是,如果我将上面的代码放在一个单独的 .lib 中,魔术就会以某种方式中断并且实现类(DummyAction 等)不再实例化。

我看到 #include "DummyAction.h" 某处,无论是在我的库中还是在主项目中,都可以正常工作,但是

  1. 对于我们的项目,强制要求添加 Actions 不需要更改其他文件。
  2. 我真的不明白幕后发生了什么,这让我很不舒服。我真的很讨厌依赖于我没有完全掌握的解决方案,因为错误可能会在任何地方、任何时间、可能在将我们的软件交付给客户前一天出现:)
  3. 更奇怪的是,在头文件中放置 #include 指令但不定义构造函数/析构函数仍然打破了魔法。

感谢大家的关注。我真的希望有人能够阐明一些...

最佳答案

我可以描述问题的原因;很遗憾,我无法提供解决方案。

问题在于,具有静态存储持续时间的变量的初始化可能会推迟到首次使用在同一翻译单元中定义的内容之前的任何时间。如果您的程序从不使用与 CCRTPAction<CDummyAction>::m_bForceRegistration 相同的翻译单元中的任何内容,那么该变量可能永远不会被初始化。

如您所见,包括定义 main 的翻译单元中的 header 将强制它在 main 开始之前的某个时间点被初始化;但当然该解决方案不能满足您的第一个要求。对于跨多个翻译单元初始化静态数据的问题,我通常的解决方案是完全避免静态数据(并且 Singleton 反模式加倍避免,尽管这是您在这里遇到的最少的问题)。

关于c++ - 在单独的库中使用 CRTP 进行静态成员初始化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17921257/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com