0
votes

For the following code, I had to use #ifdef directives to have it compile under both gcc and msvc. Is there a better way to write this w/o #ifdef directives? With gcc, the specialized templates for PushSettings need to be outside the class declaration. However, msvc only seems to except them when they are declared inside the class.

// header file

#include <iostream>
#include <map>

class SettingsManager
{
public:
    
    template <typename T>
    void PushSetting(std::string key, T* value);

    #ifdef WINDOWS
        template<>
        void PushSetting<bool>(std::string key, bool* value)
        {
            ListElement listElement{ ElementType::TYPE_BOOL, value };
            m_Settings.insert(std::make_pair(key, listElement));
        }

        template<>
        void PushSetting<std::string>(std::string key, std::string* value)
        {
            ListElement listElement{ ElementType::TYPE_STRING, value };
            m_Settings.insert(std::make_pair(key, listElement));
        }

        template<>
        void PushSetting<RendererAPI::API>(std::string key, RendererAPI::API* value)
        {
            ListElement listElement{ ElementType::TYPE_RENDERERAPI_API, value };
            m_Settings.insert(std::make_pair(key, listElement));
        }
    #endif
private:

    enum class ElementType
    {
        TYPE_INT,
        TYPE_BOOL,
        TYPE_STRING,
        TYPE_RENDERERAPI_API
    };

    struct ListElement
    {
        ElementType m_Type;
        void* m_Pointer;
    };

private:

    std::map<std::string, ListElement> m_Settings;

};
// cpp file

#include "settings.h"
#include "glm.hpp"


#ifndef WINDOWS
    template<>
    void SettingsManager::PushSetting<int>(std::string key, int* value)
    {
        ListElement listElement{TYPE_INT, value};
        m_Settings.insert(std::make_pair(key, listElement));
    }
    
    template<>
    void SettingsManager::PushSetting<bool>(std::string key, bool* value) 
    {
        ListElement listElement{TYPE_BOOL, value};
        m_Settings.insert(std::make_pair(key, listElement));
    }
    
    template<>
    void SettingsManager::PushSetting<std::string>(std::string key, std::string* value)
    {
        ListElement listElement{TYPE_STRING, value};
        m_Settings.insert(std::make_pair(key, listElement));
    }
    
    template<>
    void SettingsManager::PushSetting<RendererAPI::API>(std::string key, RendererAPI::API* value)
    {
        ListElement listElement{TYPE_RENDERERAPI_API, value};
        m_Settings.insert(std::make_pair(key, listElement));
    }
#endif
Have you tried declaring the specializations in the header file outside the class declaration, and defining them in the cpp file?Sam Varshavchik
@samv have you tried writing that as an answer?Yakk - Adam Nevraumont
No, because I don't have MSVC to verify its behavior.Sam Varshavchik
Seems to compile fine with msvc on godbolt: godbolt.org/z/7K7r8E4qs (I added ElementType:: prefix to the used enum values because it is enum class, not just enum).danadam
Sam, Yakk, The problem is gcc cannot handle the specializations declared in the header. Here's a pastebin to show you a more stripped-down example leading to the gcc error "error: explicit specialization in non-namespace scope ‘class Settings’", pastebin.com/Fv4wVB5c (Sorry for linking to an external site & thanks for the comments so far!)user13742796