简体   繁体   中英

How to declare a std::map from EnumType to EnumTypeValue?

I have an enum:

enum VehicleType {CAR, BIKE, TRUCK};

The following class uses this enum as a template parameter:

template <VehicleType V>
class ParkingSlotContainer
{
    ...
};

Now, I wish to define a class with a map data member that maps a VehicleType to ParkingSlotContainer<VehicleType> . In other words, I want to map CAR to ParkingSlotContainer<CAR> , BIKE to ParkingSlotContainer<BIKE> , etc.

This is my attempt:

class ParkingFloor
{
private:
    int floor;
    map<VehicleType, ParkingSlotContainer<VehicleType> > slots;
public:
    ParkingFloor(...);
    ...
};

The compiler doesn't accept the above and reports that type name is not allowed . It expects ParkingSlotContainer<CAR|BIKE|TRUCK> instead of ParkingSlotContainer<VehicleType> .

What is the right way to define such a map?

The problem is that you cannot have two values of different type in an std::map : For instance, you cannot have both a ParkingSlotContainer<BIKE> and ParkingSlotContainer<CAR> inside the slots variable, because they are different types.

For these kinds of situations where you want to produce types from enum values, you may want to use higher order macros . Here is an example of higher order macros applied to your code, where we use them to declare three member variables ( _CAR , _BIKE and _TRUCK ) for the three enum values and then generate overloaded methods setSlot to set a new value to any one of them. Just to demonstrate how you can use higher order macros:

#define FOREACH_VEHICLE_TYPE(OP) \
  OP(CAR) \
  OP(BIKE) \
  OP(TRUCK)

enum VehicleType {
  #define DECL_VEHICLE(name) name,
  FOREACH_VEHICLE_TYPE(DECL_VEHICLE)
  #undef DECL_VEHICLE
};

template <VehicleType V>
class ParkingSlotContainer
{
public:
  int vehicleCount = 0;
};

class ParkingFloor
{
private:
  int floor;
  
#define DECL_SLOT(name) ParkingSlotContainer<name> _##name;
FOREACH_VEHICLE_TYPE(DECL_SLOT)
#undef DECL_SLOT

public:
#define SET_SLOT(name) void setSlot(const ParkingSlotContainer<name>& newValue) {_##name = newValue;}
  FOREACH_VEHICLE_TYPE(SET_SLOT)
#undef SET_SLOT
};

int main() {
  ParkingSlotContainer<BIKE> bikes;
  bikes.vehicleCount = 119;

  ParkingFloor parkingFloor;
  parkingFloor.setSlot(bikes);
  return 0;
}

Depending on your application, this may or may not be overkill. It sort of makes the code harder to read...

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM