C++ Invert Map at Compile Time

Sometimes it’s useful to be able to invert a map in C++ to perform reverse lookup. Say you are mapping names to IDs of something:

const std::unordered_map<std::string, int> stuffMap = {
    {"bread", 100},
    {"sword", 200},
    {"lamp",  300},
    {"clogs", 400}
};

Maybe you have the ID and want to get the name. That’s something we can do by reversing the map. Inserting the reversed pairs in a loop seems like a good solution, but maybe we also want this done at compile-time! So let’s define a function which does this for us, but with an arbitrary function, so we can do any kind of transformation our hearts desire:

//Function which can transform an std::unordered_map of one type to another with a given transform function
template<typename Kout, typename Vout, typename Kin, typename Vin>
std::unordered_map<Kout, Vout> transformMap(
    const std::unordered_map<Kin, Vin>& inMap,
    const std::function<std::pair<Kout, Vout>(const std::pair<Kin, Vin>&)> mapfunc)
{
    std::unordered_map<Kout, Vout> outMap;
    std::for_each(inMap.begin(), inMap.end(),
        [&outMap, &mapfunc] (const std::pair<Kin, Vin> &p) {
            outMap.insert(mapfunc(p));
        }
    );
    return outMap;
}

We can use this function to reverse our stuffMap to allow reverse lookup, all at compile-time:

const std::unordered_map<int, std::string> revStuffMap = transformMap(stuffMap,
    std::function([](const std::pair<std::string, int>& p) {
        return std::make_pair(p.second, p.first);
    })
);

Let’s try it out:

int main() {
    std::cout << "stuffMap:" << std::endl;
    for (const auto& p : stuffMap) {
        std::cout << p.first << ":" << p.second << std::endl;
    }
    std::cout << "\nrevStuffMap:" << std::endl;
    for (const auto& p : revStuffMap) {
        std::cout << p.first << ":" << p.second << std::endl;
    }
}

stuffMap:
400:clogs
300:lamp
200:sword
100:bread

revStuffMap:
bread:100
sword:200
clogs:400
lamp:300

Try it yourself here!

And it doesn’t need to stop at reversing a map! You can use any function to transform the input to the output map. Go crazy!