【问题标题】:global extern pointer to unknown templated type指向未知模板类型的全局外部指针
【发布时间】:2021-10-19 16:22:56
【问题描述】:

背景:

我有一个游戏引擎,其中有多个 externed 全局指针指向各种子系统,以便下游游戏应用程序易于访问:

#pragma once

#include <type_traits>

class JobSystem;
class FileLogger;
class Renderer;
class Console;
class Config;
class UISystem;
class InputSystem;
class AudioSystem;
class EngineSubsystem;

class GameBase;

extern JobSystem* g_theJobSystem;
extern FileLogger* g_theFileLogger;
extern Renderer* g_theRenderer;
extern Console* g_theConsole;
extern Config* g_theConfig;
extern UISystem* g_theUISystem;
extern InputSystem* g_theInputSystem;
extern AudioSystem* g_theAudioSystem;
extern GameBase* g_theGame;
extern EngineSubsystem* g_theSubsystemHead;

template<typename GameDerived>
GameDerived* GetGameAs() noexcept {
    static_assert(std::is_base_of_v<std::remove_cv_t<std::remove_reference_t<std::remove_pointer_t<GameBase>>>, std::remove_cv_t<std::remove_reference_t<std::remove_pointer_t<GameDerived>>>>);
    return dynamic_cast<GameDerived*>(g_theGame);
}

问题:

我希望能够提供一个指向 App 类的全局指针,但该类是一个模板这一事实使得它难以理解如何实现它。

伪代码实现:

类层次结构:

#pragma once
#include <type_traits>

class GameBase { /*...*/ }
class Game : public GameBase { /*...*/ }

template<typename GameType>
class App {
static_assert(std::is_base_of_v<GameBase, GameType>, "Template type GameType not derived from GameBase.");

public:

static void CreateApp() {
    if(_theApp) {
        return;
    }
    _theApp = new App<T>();
}

static void DestroyApp() {
    if(!_theApp) {
        return;
    }
    delete _theApp;
    _theApp = nullptr;
}

//...

private:

    void SetupSubsystemPointers() {
        
        //...
        
        _theRenderer = std::make_unique<Renderer>();
        g_theRenderer = _theRenderer.get();
        
        //...
        
        _theGame = std::make_unique<GameType>();
        g_theGame = _theGame.get();

        //...This does not work:
        //g_theApp = this;
    }

    std::unique_ptr<JobSystem> _theJobSystem{};
    std::unique_ptr<FileLogger> _theFileLogger{};
    std::unique_ptr<Config> _theConfig{};
    std::unique_ptr<Renderer> _theRenderer{};
    std::unique_ptr<Console> _theConsole{};
    std::unique_ptr<InputSystem> _theInputSystem{};
    std::unique_ptr<UISystem> _theUI{};
    std::unique_ptr<AudioSystem> _theAudioSystem{};
    std::unique_ptr<GameType> _theGame{};

    //I would really like this to be a std::unique_ptr.
    static inline App<GameType>* _theApp{};

}

这是我在实现指向 App 类的全局指针时遇到的麻烦。

通用标题:

#pragma once

#include <type_traits>

class JobSystem;
class FileLogger;
class Renderer;
class Console;
class Config;
class UISystem;
class InputSystem;
class AudioSystem;
class EngineSubsystem;

class GameBase;

extern JobSystem* g_theJobSystem;
extern FileLogger* g_theFileLogger;
extern Renderer* g_theRenderer;
extern Console* g_theConsole;
extern Config* g_theConfig;
extern UISystem* g_theUISystem;
extern InputSystem* g_theInputSystem;
extern AudioSystem* g_theAudioSystem;
extern GameBase* g_theGame;

// WHAT DO I NEED TO DO TO GET SOMETHING LIKE THE FOLLOWING TO WORK?
//extern App* g_theApp;

//I tried
//template<typename GameType>
//App<GameType>* g_theApp but compilation failed with an undefined variable error or template vomit errors.
//extern GameType* g_theGame; //This would be nice to have. It would replace the above GameBase pointer and the below GetGameAs function

extern EngineSubsystem* g_theSubsystemHead;

template<typename GameDerived>
GameDerived* GetGameAs() noexcept {
    static_assert(std::is_base_of_v<std::remove_cv_t<std::remove_reference_t<std::remove_pointer_t<GameBase>>>, std::remove_cv_t<std::remove_reference_t<std::remove_pointer_t<GameDerived>>>>);
    return dynamic_cast<GameDerived*>(g_theGame);
}

常见实现:

#include "Engine/Core/EngineCommon.hpp"

JobSystem* g_theJobSystem = nullptr;
FileLogger* g_theFileLogger = nullptr;
Renderer* g_theRenderer = nullptr;
Console* g_theConsole = nullptr;
Config* g_theConfig = nullptr;
UISystem* g_theUISystem = nullptr;
InputSystem* g_theInputSystem = nullptr;
AudioSystem* g_theAudioSystem = nullptr;
GameBase* g_theGame = nullptr;
EngineSubsystem* g_theSubsystemHead = nullptr;

//DOES NOT WORK
//App* g_theApp = nullptr;

【问题讨论】:

  • template&lt;typename GameType&gt; App&lt;GameType&gt;* g_theApp 应该可以工作。看起来您忘记在公共标头中转发声明 App
  • 另外,如果您支持 C++17,您可以将所有这些外部变量改为内联变量,这样您就可以在头文件中定义它们。
  • 那些不透明的前向声明类是怎么回事?为什么不包括相关的类定义?另外,为什么你需要它们全局?它们似乎属于 App 类。
  • @SergeyA 全局访问,供下游游戏直接使用。 App 类只管理它们的生命周期。
  • @NathanOliver 将您的评论作为答案,我会接受。

标签: c++ pointers templates global-variables extern


【解决方案1】:

template&lt;typename GameType&gt; App&lt;GameType&gt;* g_theApp; 应该适合你。您似乎忘记在公共标头中转发声明 App,这就是您无法声明指向它的指针的原因。

另外,如果你可以使用 C++17,你可以停止使用 extern 并开始在你的所有变量声明中使用 inline 并将它们转换成类似的定义

inline JobSystem* g_theJobSystem = nullptr;
inline FileLogger* g_theFileLogger = nullptr;
inline Renderer* g_theRenderer = nullptr;
inline Console* g_theConsole = nullptr;
inline Config* g_theConfig = nullptr;
inline UISystem* g_theUISystem = nullptr;
inline InputSystem* g_theInputSystem = nullptr;
inline AudioSystem* g_theAudioSystem = nullptr;
inline GameBase* g_theGame = nullptr;
inline EngineSubsystem* g_theSubsystemHead = nullptr;

inline 将告诉编译器可以在多个翻译单元中定义变量,链接器会将它们全部合并为一个,就像它对内联函数所做的那样。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多