开发者

Writing preprocessor directives to get string

Can you write preprocessor directives to return you a std::string or char*?

For example: In case of integers:

#define square(x) (x*x)

int main()
{
   int x = square(5);
}

I'm looking to开发者_JS百科 do the same but with strings like a switch-case pattern. if pass 1 it should return "One" and 2 for "Two" so on..


You don't want to do this with macros in C++; a function is fine:

char const* num_name(int n, char const* default_=0) {
  // you could change the default_ to something else if desired

  static char const* names[] = {"Zero", "One", "Two", "..."};
  if (0 <= n && n < (sizeof names / sizeof *names)) {
    return names[n];
  }
  return default_;
}

int main() {
  cout << num_name(42, "Many") << '\n';
  char const* name = num_name(35);
  if (!name) { // using the null pointer default_ value as I have above
    // name not defined, handle however you like
  }
  return 0;
}

Similarly, that square should be a function:

inline int square(int n) {
  return n * n;
}

(Though in practice square isn't very useful, you'd just multiply directly.)


As a curiosity, though I wouldn't recommend it in this case (the above function is fine), a template meta-programming equivalent would be:

template<unsigned N> // could also be int if desired
struct NumName {
  static char const* name(char const* default_=0) { return default_; }
};
#define G(NUM,NAME) \
template<> struct NumName<NUM> { \
  static char const* name(char const* default_=0) { return NAME; } \
};
G(0,"Zero")
G(1,"One")
G(2,"Two")
G(3,"Three")
// ...
#undef G

Note that the primary way the TMP example fails is you have to use compile-time constants instead of any int.


A #define preprocessor directive does substitute the string of characters in the source code. The case...when construct you want is still not trivial:

#define x(i) ((i)==1?"One":((i)==2?"Two":"Many"))

might be a start -- but defining something like

static char* xsof[] = ["One", "Two", "Many"];

and

#define x(i) xsof[max(0, min((i)-1, (sizeof xsof / sizeof xsof[0] - 1)))]

seems more reasonable and better-performing.

Edit: per Chris Lutz's suggestion, made the second macro automatically adjust to the xsof definition; per Mark's, made the count 1-based.


I have seen this...

#define STRING_1() "ONE"
#define STRING_2() "TWO"
#define STRING_3() "THREE"
...

#define STRING_A_NUMBER_I(n) STRING_##n()

#define STRING_A_NUMBER(n) STRING_A_NUMBER_I(n)  

I belive this extra step is to make sure n is evaluated, so if you pass 1+2, it gets transformed to 3 before passed to STRING_A_NUMBER_I, this seems a bit dodge, can anyone elaborate?


You cannot turn integers into strings so 1 ---> "One", 2 ---> "Two", etc except by enumerating each value.

You can convert an argument value into a string with the C preprocessor:

#define STRINGIZER(x)   #x
#define EVALUATOR(x)    STRINGIZER(x)
#define NAME(x)         EVALUATOR(x)

NAME(123)    // "123"

#define N   123
#define M   234

NAME(N+M)    // "123+234"

See also SO 1489932.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜