c++enum-classc++-templates

Trying to create a generic cast to str for several enum classes


I'm trying to create a generic function toStr() for several enum classes but I'm having some issues.

I have these enum classes and maps to convert the value of the enums to string.

'''

enum class InitFields : int32_t
{
    userRightsPath = 1,
    configurationDataPath,
    configFile
};

static std::map<InitFields, QString>  s_initField2str
{
    {InitFields::rhSystem, "rhSystem"},
    {InitFields::number, "number"},
    {InitFields::userRightsPath,"userRightsPath"}
};

enum class UserRole : int32_t
{
    Administrator=1,
    Superuser,
    Operator
};

static std::map<UserRole, QString> s_userRole2str
{
    {UserRole::Operator, "Operator"},
    {UserRole::Administrator,"Administrator"},
    {UserRole::Superuser,"Super-User"}
};
'''

So my first option was trying to create just one function

'''
template <typename T>
static QString const toStr(T enumt)
{
    QString value = "";

    if (std::is_same<T, InitFields>())
    {
        value = s_initField2str[enumt];
    }
    else if (std::is_same<T, UserRole>())
    {
        value = s_userRole2str[enumt];
    }
    else 
    {
        value = "Error converting the enum";
    }

    return value:
}
'''

While using this function I get compiling errors because the compiler resolves the type at compile time and there is always a type accesing a map that is not correct. I understand that.

So my second alternative was specializing toStr() with each enum type but I got multiple definitions while compiling.

'''

template <typename T>
static QString const toStr(T enumt)
{
    return "Error converting the enum";
}

template <>
static QString const toStr<InitFields>(InitFields enumt)
{
     return s_initField2str[enumt];
}

template<>
QString const toStr<UserRole>(UserRole enumt)
{
    return s_userRole2str[enumt];
}

'''

Is what I'm trying even possible? Could you shed some light about this?

Many thanks


Solution

  • First options requires C++17 and if constexpr:

    template <typename T>
    static QString const toStr(T enumt)
    {
        if constexpr (std::is_same<T, InitFields>())
        {
            return s_initField2str[enumt];
        }
        else if constexpr (std::is_same<T, UserRole>())
        {
            return s_userRole2str[enumt];
        }
        else 
        {
            return "Error converting the enum";
        }
    }
    

    So my second alternative was specializing toStr() with each enum type but I got multiple definitions while compiling.

    template are implicitly inline, but not specialization, so you need inline to avoid multiple definition:

    template <typename T>
    QString toStr(T enumt)
    {
        return "Error converting the enum";
    }
    
    template <>
    inline QString toStr<InitFields>(InitFields enumt)
    {
         return s_initField2str[enumt];
    }
    
    template<>
    inline QString toStr<UserRole>(UserRole enumt)
    {
        return s_userRole2str[enumt];
    }
    

    Alternative would be simple overloads:

    template <typename T>
    QString toStr(T enumt) // = delete;
    {
        return "Error converting the enum";
    }
    
    inline QString toStr(InitFields enumt)
    {
         return s_initField2str[enumt];
    }
    
    inline QString toStr(UserRole enumt)
    {
        return s_userRole2str[enumt];
    }