4

I have a list of pre-defined mappings of string constants to numbers outside of my code base. The integers map to data inside of the program but I want to use the far more readable string constants in my code. The resulting binary should only contain the numbers and not contain the string constants at all. Is it possible to replace the string constants with the mapped integer at compile time?

What I want to achieve is basically having this code:

getData("a string constant here");

and I want to transform it into this:

getData(277562452);

Is this possible via macros or constexpr?

Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
xen
  • 625
  • 1
  • 7
  • 18
  • 6
    Why not just use named constants? A file with lines of `const int a_string_constant_here = 277562452;` etc. – amaurea Jun 28 '16 at 19:40

5 Answers5

5
#define astrconst 277562452

Or

enum Strs { astrconst = 277562452 };
Ivan Rubinson
  • 3,001
  • 4
  • 19
  • 48
4

You could use a custom suffix (see user-defined literals)

This would be used like this:

getData("a string constant here"_hash);

or simply use a consexpr hash function:

getData(hash("a string constant here"));

There is examples of constexpr hash functions out there

edit: If the mapping is already defined, my answer wont help much...

Community
  • 1
  • 1
johan d
  • 2,798
  • 18
  • 26
  • 1
    Even if it won't help much for this requirement, I learned about user-defined literals. Thanks for posting this! – xen Jun 29 '16 at 21:28
1

You can do it with a macro that you define either internally, like this

#define A_STRING_CONSTANT_HERE 277562452

or externally on the command line. The command line is compiler-dependent. For GNU compilers you would use the -D directive, i.e.

g++ -DA_STRING_CONSTANT_HERE=277562452 myprog.cpp

Then you use it like this:

getData(A_STRING_CONSTANT_HERE);

The name of your constant will not be part of your code; it would be replaced with the numeric value, as if you wrote

getData(277562452);
Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
1

Just use const auto a_string_constant_here = 277562452;. Then use a_string_constant_here whenever you want to refer to the constant.

Jesper Juhl
  • 30,449
  • 3
  • 47
  • 70
1

I think that solution based on enums (see Ivan Rubinson) or defines (see dasblinkenlight) are preferable.

But if you really want to use C-style string in your code, and throw they away in compiling fase, I propose the following solution, based on a constexpr function and three macro function

#include <iostream>

constexpr int strCmp (char const * s1, char const * s2)
 {
   return ((0 == *s1) && (0 == *s2))
      ? 0
      : ((*s1 == *s2) || ((*s1 == ' ') && (*s2 == '_')))
        ? strCmp(s1+1, s2+1)
        : (*s1 - *s2);
 }

#define  string_constant_1   123456
#define  string_constant_2   345678
#define  string_constant_3   567890

#define IfFragm(c, i)    ( 0 == c ) ? i
#define ChkStr(STR, CST) IfFragm(strCmp(STR, #CST), CST)

#define GetIntValue(STR) (ChkStr(STR, string_constant_1) \
                          : ChkStr(STR, string_constant_2) \
                          : ChkStr(STR, string_constant_3) \
                          : 0)

int main ()
 {
   std::cout << "val 1 = " << GetIntValue("string constant 1") << std::endl;
   std::cout << "val 2 = " << GetIntValue("string constant 2") << std::endl;
   std::cout << "val 3 = " << GetIntValue("string constant 3") << std::endl;

   return 0;
 }

The strCmp() constexpr function is roughly equivalent to std::strcmp() but with the difference that a space in the left string is considered equal to an underscore in the right string.

Next you can create your maps string/number using defines

#define  string_constant_1   123456

were the macro string_constant_1 correspond to the C-style string ("string constant 1"). I mean: the spaces in the string are become underscores in the macro name.

The macro functions GetIntValue(), ChkStr() and IfFragm() are doing the dirty work.

But I think that macros are evil part of C/C++ so I suggest the enum or simply define based solution.

p.s.: sorry for my bad English.

max66
  • 65,235
  • 10
  • 71
  • 111
  • Thank you for posting this! I chose to go with an enum based approach because it's pretty easy to generate that from the input data I have and this solution, while seemingly exactly what I wanted, looks quite daunting and I'm sure I can't remember what it does 5 months down the line :D – xen Jun 29 '16 at 21:27
  • @xen - good choice; I think the enum based it's the better approach and I have upvoded the Ivan Rubinsons's solutions; I proposed my solution only because was challenging to realize, but I don't think it's a good solution. – max66 Jun 29 '16 at 22:34