std::unordered_map using enum and defined class

时间:2016-04-04 16:38:52

标签: c++ class c++11 enums unordered-map

I'm trying to define a std::unordered_map using an enum class as the key and a defined class as the referenced object:

std::unordered_map<Dimension, unit, EnumClassHash> SI_Dim;
SI_Dim[Dimension::MASS] = BaseSIUnits::kilogram;

Dimension is an enum class declared in a separate header file as

enum class Dimension{MASS, TIME, LENGTH, TEMPERATURE, CURRENT, QUANTITY, ANGLE, FORCE, ENERGY, POWER,
                 AREA, VOLUME, NONDIMENSIONAL};

with EnumClassHash as a hashing function (which I can post the code for if it's relevant).

BaseSIUnits::kilogram is defined a few lines above this as

const unit BaseSIUnits::kilogram = unit(1, "kg", Dimension::MASS);

which compiles just fine. But the SI_Dim[Dimension::MASS] = BaseSIUnits::kilogram; line gives me an error. In QtCreator (my IDE) it says "expected a declaration" and g++ gives the error "SI_Dim does not name a type." Neither of these make any sense to me. Also, when looking at the line in QtCreator, neither Dimension::MASS or BaseSIUnits::kilogram is highlighted (almost as if they're unrecognized, even though I know they are). I don't have much experience with std::unordered_map, so this is probably some simple syntax error I'm missing. But the syntax looks right to me based on examples I've looked at.

1 个答案:

答案 0 :(得分:1)

As Praetorian noted in the comment, you can't really have code outside of functions in C++ (except for initializing global/static variables). If you need such code (i.e., code that cannot be written as initialization), then you can write a function init_si_dim which is required to be called (once) prior to use. See this question for a way of automating this through a global object of an ad-hoc class that does the initialization in the constructor.

On a separate direction, the use of an unordered map for your type of enum, seems a bit odd. Given that you have so few values, and are not assigning specific integer values to the enum values, I think that you're better off with a random-access container, e.g., through std::array.

Consider the following code

#include <array>                                                                                                                            

enum class dimension{mass, time, length};

inline constexpr std::size_t dimension_to_index(dimension d)
{
    return static_cast<std::size_t>(d) - static_cast<std::size_t>(dimension::mass);
}

struct foo{};

std::array<foo, 1 + dimension_to_index(dimension::length)> v;

int main()
{
    v[dimension_to_index(dimension::time)];
}   

We first have the enum, then a safe function for converting its values to indices. We then define an array object. As you can see in main, it's possible now to access the array elements via the enum values.