John John - 1 year ago 53
C++ Question

How to convert a string to a constant integer?

I have strings which represent image names like "foobar.png" etc.
As you know, switch-case in C++ does not support switching on a string.

I'm trying to work around this, by hashing the string to std::size_t, and then using that value in the switch-case statements.

For example:

//frameName is an std::string which represents foobar.png etc..
switch (shs(frameName)) { //shs is my hash func which returns std::size_t;
case shs(Pfn::fs1x1): //Problem in this line

In a separate file (Pfn.hpp):

namespace Pfn{
const std::string fs1x1 = "fs1x1";

The problem is, that in my case statement the compiler reports that
is not a constant expression. The exact error message is:

Case value is not a constant expression:

It would be really tedious to work out all the hash-values in advance and then hardcode them into the case statements. Do you have a suggestion on how I can somehow create the constant expressions at runtime ?

EDIT: My shs function:

static std::size_t shs(std::string string){
return Hash::shs::hs(string);


namespace Hash{
struct shs{
inline std::size_t operator()(const std::string &string)const{
return hashString(string);

static std::size_t hs(const std::string &string){
std::size_t seed = 0;
return seed;

//From Boost::hash_combine.
template <class T>
static inline void hash_combine(std::size_t& seed, const T& v)
std::hash<T> hasher;
seed ^= hasher(v) + 0x9e3779b9 + (seed<<6) + (seed>>2);

Answer Source

shs's argument needs to be constexpr and shs itself must be constexpr as well. Chances are, you might want to provide different implementations for the compile-time version and the run-time version of the hash, due to C++11 constraints on constexpr functions.

I wrote a post on this very topic some time ago, using fnv1a as the hash algorithm. Here are the important parts:


typedef std::uint64_t hash_t;

constexpr hash_t prime = 0x100000001B3ull;
constexpr hash_t basis = 0xCBF29CE484222325ull;

Runtime hash:

hash_t hash(char const* str)
    hash_t ret{basis};

        ret ^= *str;
        ret *= prime;

    return ret;

Compile-time hash:

constexpr hash_t hash_compile_time(char const* str, hash_t last_value = basis)
    return *str ? hash_compile_time(str+1, (*str ^ last_value) * prime) : last_value;

user defined string literal:

constexpr unsigned long long operator "" _hash(char const* p, size_t)
    return hash_compile_time(p);

and usage:

case "first"_hash:
    cout << "1st one" << endl;
case "second"_hash:
    cout << "2nd one" << endl;
case "third"_hash:
    cout << "3rd one" << endl;
    cout << "Default..." << endl;


But please, think of the children! Unless you can guarantee that there will be no hash collisions, this is playing with fire and is not fit to be production code.