首页 > 解决方案 > 指向未知模板类型的全局外部指针

问题描述

背景:

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

#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;

标签: c++pointerstemplatesglobal-variablesextern

解决方案


template<typename GameType> App<GameType>* 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将告诉编译器可以在多个翻译单元中定义变量,链接器会将它们全部合并为一个,就像它对内联函数所做的那样。


推荐阅读