Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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.

like image 691
danijar Avatar asked Nov 03 '13 21:11

danijar


3 Answers

You realize you can initialize maps from braced lists?

std::unordered_map<std::string, std::string> m { { "a", "bc" }
                                               , { "b", "xy" }
//                                               ...
                                               };
like image 64
Kerrek SB Avatar answered Nov 13 '22 02:11

Kerrek SB


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.

like image 42
Jonathan Wakely Avatar answered Nov 13 '22 03:11

Jonathan Wakely


Visual C++ now supports static initialization from braced lists, so you could do something like this:

const std::unordered_map<std::string, std::string> ManagerDataTrait<Person>::Fields{ { "abc", "xyz" }, { "cde", "zyx" } ...};
like image 2
NiRuKa Avatar answered Nov 13 '22 02:11

NiRuKa