3

These preprocessor and template limitations of c++ are killing me. The goal is to convert string literals into integers.

template<const char* str>
inline int LiteralToInt(){
    return __COUNTER__;
}

using std::cout;

int main(){
    cout << LiteralToInt<"Hello">();
    cout << LiteralToInt<"No">();
    cout << LiteralToInt<"Hello">();
    return 0;
}

The output would be 010 if templates accepted string literals. Is there another way to get this output and convert string literals to integers at compile time?

Michael Graczyk
  • 4,905
  • 2
  • 22
  • 34
user936509
  • 213
  • 3
  • 8
  • If you use the address of the literal, it could just as well produce `012`. Merging identical string literals is not required by the language. And if `__COUNTER__` is the VC++ macro, it would likely be `111` becuse the macro is expanded only once. – Bo Persson Aug 03 '12 at 07:11
  • even if most compilers do merge identical literals, they don't do it for different translation units. Too much hassle and too little gain. – pqnet Sep 03 '14 at 14:45

4 Answers4

3

Yes, C++ 11's constexpr will do this for you:

 constexpr int LiteralToInt(const char * str) {
      return __COUNTER__; // or whatever.
 }
Richard J. Ross III
  • 55,009
  • 24
  • 135
  • 201
1

Something like this would work

extern const char HELLO[] = "Hello";

and then

cout << LiteralToInt<HELLO>();

but not the literal itself. This is probably not what you want.

String literals themselves, as you already discovered, cannot be used as template arguments.

AnT stands with Russia
  • 312,472
  • 42
  • 525
  • 765
1

A little bit of thinking about Richard J Ross III's answer using constexpr gave me the right key to search with... What you're essentially doing is hashing a string at compile time. You can do this in C++11 (but not earlier versions) as shown here.

The basic idea is to use something like this:

unsigned int constexpr const_hash(char const *input) { 
    // really simple hash function...
    return static_cast<unsigned int>(*input) 
         && static_cast<unsigned int>(*input) + hash(input+1); 
}

But you probably want to use a hash function with more robust properties than this...

However if you're not using C++11 then my earlier statement holds:

No - there is no way to convert string literals to integers at compile time, in such a way that all of the same strings map to same values, (and different strings map to different values) across all compilation units, short of processing the code in some way.

Community
  • 1
  • 1
Michael Anderson
  • 70,661
  • 7
  • 134
  • 187
0

Unfortunately, I know of no way to do exactly what you want.

Are there any restrictions you can put on the strings? Like number of characters? If you can limit it to 1-8 characters, you can do something like this:

template <char Ch1, char Ch2 = '\0', char Ch3 = '\0', char Ch4 = '\0', char Ch5 = '\0', char Ch6 = '\0', char Ch7 = '\0', char Ch8 = '\0'>
struct string_hash {
    static const uint64_t value = 
        (static_cast<uint64_t>(Ch1) << 56) | 
        (static_cast<uint64_t>(Ch2) << 48) | 
        (static_cast<uint64_t>(Ch3) << 40) | 
        (static_cast<uint64_t>(Ch4) << 32) | 
        (static_cast<uint64_t>(Ch5) << 24) | 
        (static_cast<uint64_t>(Ch6) << 16) | 
        (static_cast<uint64_t>(Ch7) << 8)  | 
        (Ch8);
};

which basically, at compile time stuff up to 8 characters into a uint64_t. Usage would look like this:

const uint64_t x = string_hash<'T', 'e', 's', 't'>::value

This will create a compile time numeric value (can be used in a switch and all that goodness) unique to each string 1-8 chars long. Unfortunately, the only big downside is that you can't write it as a string literal, you need to write it as a list of chars

Evan Teran
  • 87,561
  • 32
  • 179
  • 238
  • The impetus behind this is to make my life easier. This is a valid way of doing it albeit unproductive. If it was really important i could do it like this. – user936509 Aug 03 '12 at 04:59
  • Accepted as a work around until constexpr gets widespread implementation. – user936509 Aug 04 '12 at 05:09