Search code examples
c++static-memberstemplate-specializationunordered-maptype-traits

How to initialize a static std::unordered_map of a type trait?


Given the following type trait, how can I initialize Fields with some std::pairs?

template <>
struct ManagerDataTrait<Person>
{
    static const std::unordered_map<std::string, std::string> Fields;
    // ...
};

I tried using a lambda but Visual Studio says that Fields is not an entity that can be explicitly specialized.

template <>
const std::unordered_map<std::string, std::string> ManagerDataTrait<Person>::Fields = []{
    std::unordered_map<std::string, std::string> fields;
    fields.insert(std::make_pair("height", "FLOAT"));
    fields.insert(std::make_pair("mass", "FLOAT"));
    return fields;
};

If there is no way to use static members like this in traits, which alternatives do I have to store the information in a trait? (Fields holds a SQL database structure.)

Update: The member might be also const but that shouldn't be the point.


Solution

  • Kerrek SB's answer would be the right answer in general:

    const std::unordered_map<std::string, std::string> ManagerDataTrait<Person>::Fields{
      { "blah", "blah" }
      // ...
    };
    

    (N.B. no template<> because you're defining a member of a specialization, not a specialization)

    But that isn't supported by Visual C++, so the other alternative is to initialize the map with a function call, and return a map with the desired contents from the function:

    std::unordered_map<std::string, std::string>
    getFields()
    {
      std::unordered_map<std::string, std::string> fields;
      fields["blah"] = "blah";
      // ...
      return fields;
    }
    
    const std::unordered_map<std::string, std::string> ManagerDataTrait<Person>::Fields = getFields();
    

    A lambda is just syntactic sugar for doing the same thing, and I'm not sure it's clearer to use a lambda because the syntax is a bit uglier.