2

I am writing a class for generating bitmask from a table of predefined element strings:

const std::unordered_map<std::string, int> flagMap
{ { "bananas", 0x1 }, { "apples", 0x2 }, { "oranges", 0x4 }, { "pears", 0x8 }};

int fruitMask(std::string & fruitName)
{
    if(flagMap.count(fruitName) > 0)
        return flagMap.at(fruitName);
    else
        return 0;
}

int fruitMask(const char * fruitName)
{
    if(flagMap.count(fruitName) > 0)
        return flagMap.at(fruitName);
    else
        return 0;
}    

int fruitMask(std::vector<std::string> fruitNames)
{
    int result = 0;

    for(auto it=fruitNames.begin(); it!=fruitNames.end(); ++it)
    {
        if(flagMap.count(*it) > 0)
            result = result | flagMap.at(*it);
    }

    return result;
} 

int fruitMask(std::initializer_list<const char*> fruitNames)
{
    int result = 0;

    for(auto it=fruitNames.begin(); it!=fruitNames.end(); ++it)
    {
        if(flagMap.count(*it) > 0)
            result = result | flagMap.at(*it);
    }

    return result;
}    

When the code using these functions call the const char* or the std::initializer_list<const char*> versions of fruitMask, is there any way to make it work at compile time?

For instance:

constexpr int mask = flagMask({"oranges", "bananas"}); 

This will not compile because flagMask() is not constexpr, is there any way to make this work? This would require a constexpr unordered_map, I do not even know if this is possible.

Kirill Kobelev
  • 10,252
  • 6
  • 30
  • 51
galinette
  • 8,896
  • 2
  • 36
  • 87
  • I believe this is not possible. You ask for too complex computation at compile time. Compiler is not intended to perform any calculation. – Kirill Kobelev Jan 09 '17 at 17:34
  • its not only about unordered map but about your keys, const char* does not really mean compile-time string in general case, would you consider changing key type – Oleg Bogdanov Jan 09 '17 at 20:51

1 Answers1

0

Compile time strings were discussed here


Maybe not an answer per se but (hopefully) a helpful hint. Its not only about unordered map in your case but about your keys, const char* does not really mean compile-time string in general case, would you consider changing key type? Lets consider enum-ed keys (and very not optimal quadratic search, sorry):

#include <utility>

enum class keys : char 
{
   foo,
   bar,
   baz,
   lol
};

static constexpr std::pair<keys, int> flagMap[] = {
  {keys::foo, 42},
  {keys::bar, 24},
  {keys::baz, 100500},
  {keys::lol, 15234}
};

static constexpr int sum(std::initializer_list<keys> target)
{
  int res{0};
  for (auto key: target) { 
    for (int i = 0; i < 4; ++i)
    {
      res += (flagMap[i].first == key) ? flagMap[i].second : 0;
    }
  }
  return res;
}

int main()
{
  return sum({keys::foo, keys::baz});
}

Demo yields just

mov     eax, 100542
ret

at -O1 and up

Community
  • 1
  • 1
Oleg Bogdanov
  • 1,712
  • 13
  • 19