简体   繁体   中英

Ensuring coverage for all enum values in map

Say I have the following:

#include <map>

enum class Thing {Zero, One, Two};

class Metadata {};

std::map<Thing, Metadata> extra_info;

void foo() {
    extra_info[Thing::Zero] = Metadata();
    extra_info[Thing::One] = Metadata();
    extra_info[Thing::Two] = Metadata();
}

I would like to ensure that all tags of Thing are accounted for in extra_info , in the event that a new tag is added, like Thing::Three .

I considered always having a tag at the end, LastTag , and iterating from 0 to LastTag - 2 and verifying that those keys exist in the map, but this seems kludgy. A way to accomplish this at compile time would be best, but I can see this not being possible, at all.

In C#, it's a simple thing to use reflection to get all the enum values, then iterate over these. I think it's telling that I can't find an answer for this with the C++ tag, but I can find answers for Java and C#... Which makes me think this isn't possible.

Sentinel values in enums have been part of many projects to indicate the number of enum values or to delimit a range of user-available enums from the system-defined ones.

In your case you can exploit the fact that a map has unique keys and add a sentinel value (strictly not part of the enum):

enum class Thing { Zero, One, Two, Three, EndSentinel };

class Metadata {};

std::map<Thing, Metadata> extra_info;
typedef std::map<Thing, Metadata>::size_type map_type;

void foo() {
    // Can't forget these values
    extra_info[Thing::Zero] = Metadata();
    extra_info[Thing::One] = Metadata();
    extra_info[Thing::Two] = Metadata();
    extra_info[Thing::Three] = Metadata();
}

int main() {
    foo();

    assert(extra_info.size() == (map_type)Thing::EndSentinel);
}

Example

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