0

I am trying to create a std::map which maps an enum to a string (an enum of database types and their type name strings).

I have a enum class with each type, and a class with two public static function to convert from type to string and string to type.

If I make the definition of the map static I get the error a static data member with an in-class initializer must have non-volatile const integral type or be specified as 'inline' (I can't use inline because I am stuck with C++11)

Header file:

enum class DBDataType {
    Unset,
    Boolean,
    Character,
    Date,
    Double,
    Integer,
    Time,
    TimeStamp,
};

class DB_DT {
public:
    static std::string Type2Str(DBDataType type);
    static DBDataType Str2Type(std::string name);
private:
    static std::map<DBDataType, std::string> typeStringMap {
        {DBDataType::Boolean, "BOOLEAN"},
        {DBDataType::Character, "CHAR"},
        {DBDataType::Date, "DATE"},
        {DBDataType::Double, "DOUBLE"},
        {DBDataType::Integer, "INTEGER"},
        {DBDataType::Time, "TIME"},
        {DBDataType::TimeStamp, "TIMESTAMP"},
    };
    DB_DT();
};

CPP File:

std::string DB_DT::Type2Str(DBDataType type)
{
    auto pos = typeStringMap.find(type);
    if (pos == typeStringMap.end()) {
        return "";
    }
    else {
        return pos->second;
    }
}

DBDataType DB_DT::Str2Type(std::string name)
{
    for (auto it = typeStringMap.begin(); it != typeStringMap.end(); ++it) {
        if (it->second.compare(name)) {
            return it->first;
        }
    }
    return DBDataType::Unset;
}

So I changed the header declaration to static std::map<DBDataType, std::string> typeStringMap; create a function to fill the map if it is empty, which is checked from the converter functions:

std::string DB_DT::Type2Str(DBDataType type)
{
    if (typeStringMap.empty()) {
        createMap();
    }

    auto pos = typeStringMap.find(type);
    if (pos == typeStringMap.end()) {
        return "";
    }
    else {
        return pos->second;
    }
}

DBDataType DB_DT::Str2Type(std::string name)
{
    if (typeStringMap.empty()) {
        createMap();
    }

    for (auto it = typeStringMap.begin(); it != typeStringMap.end(); ++it) {
        if (it->second.compare(name)) {
            return it->first;
        }
    }
    return DBDataType::Unset;
}

void DB_DT::createMap()
{
    typeStringMap.emplace(DBDataType::Boolean, "BOOLEAN");
    typeStringMap.emplace(DBDataType::Character, "CHAR");
    typeStringMap.emplace(DBDataType::Date, "DATE");
    typeStringMap.emplace(DBDataType::Double, "DOUBLE");
    typeStringMap.emplace(DBDataType::Integer, "INTEGER");
    typeStringMap.emplace(DBDataType::Time, "TIME");
    typeStringMap.emplace(DBDataType::TimeStamp, "TIMESTAMP");
}

Which gives me the helpful error LNK2001: unresolved external symbol "private: static class std::map<DBDataType, std::string>

I don't understand this linking error, what exactly is wrong with this implementation? Would I be better off moving the definition of the map outside of the class?

6
  • 1
    You need to define your static in your cpp file, you can initialise it there as well (though be aware of the initialisation order) Commented Jul 15, 2022 at 14:14
  • Sorry to do this, but are you sure you need a run-time map for this? Why not a compile-time mapping? Why do you need to convert a string to a type? And because there's only a few types here, this could be handled simpler and more efficiently by a function with a few ifs. Have I misunderstood something?
    – Elliott
    Commented Jul 15, 2022 at 14:36
  • @Elliott any examples of what you mean by compile time mapping? The original implementation of this was done with a bunch of #define macros which I felt was unclear. There are only a few types in my example, but more in the actual implementation.
    – MikeS159
    Commented Jul 15, 2022 at 14:41
  • I mean something like this: godbolt.org/z/o3dhhqxbz
    – Elliott
    Commented Jul 15, 2022 at 15:49
  • I get the idea, but from a maintainability aspect I thing that isn't ideal. It would be harder to add new types and I feel is less readable/obvious at the intent.
    – MikeS159
    Commented Jul 15, 2022 at 15:54

0

Browse other questions tagged or ask your own question.