编写预处理器指令来获取字符串

发布于 2024-08-24 12:33:32 字数 230 浏览 5 评论 0原文

您可以编写预处理器指令来返回 std::string 或 char* 吗?

例如: 对于整数:

#define square(x) (x*x)

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

我希望做同样的事情,但是使用像 switch-case 模式这样的字符串。如果传递 1,则应返回“一”,如果传递 2,则返回“二”,依此类推。

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 do the same but with strings like a switch-case pattern. if pass 1 it should return "One" and 2 for "Two" so on..

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

梦中楼上月下 2024-08-31 12:33:32

您不想使用 C++ 中的宏来执行此操作;一个函数就可以:

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;
}

同样,那个 square 应该是一个函数:(

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

虽然在实践中 square 不是很有用,但你只需直接相乘即可。)


出于好奇,虽然我不会在这种情况下推荐它(上面的函数很好),但模板元编程等效项是:

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

请注意,TMP 示例失败的主要方式是您必须使用编译时常量而不是任何 int 。

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.

长发绾君心 2024-08-31 12:33:32

#define 预处理器指令确实会替换源代码中的字符串。您想要的 case...when 构造仍然不是微不足道的:

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

可能是一个开始 - 但定义类似

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

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

的东西似乎更合理且性能更好。

编辑:根据 Chris Lutz 的建议,使第二个宏自动调整为 xsof 定义;根据马克的说法,计数从 1 开始。

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.

冬天旳寂寞 2024-08-31 12:33:32

我已经看到了这个...

#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)  

我相信这个额外的步骤是为了确保 n 被评估,所以如果你传递 1+2,它会在传递给 STRING_A_NUMBER_I 之前转换为 3,这似乎有点躲闪,有人能详细说明吗?

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?

巷雨优美回忆 2024-08-31 12:33:32

您无法将整数转换为字符串,因此 1 ---> “一”、2---> “二”等,但枚举每个值除外。

您可以使用 C 预处理器将参数值转换为字符串:

#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"

另请参阅 SO 1489932

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文