Написание директив препроцессора для получения строки - PullRequest
0 голосов
/ 11 марта 2010

Можете ли вы написать директивы препроцессора, чтобы вернуть вам std :: string или char *?

Например: в случае целых чисел:

#define square(x) (x*x)

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

Я собираюсь сделать то же самое, но со строками, похожими на шаблон переключателя. если пройти 1, он должен вернуть «One» и 2 для «Two» и т. д.

Ответы [ 4 ]

2 голосов
/ 11 марта 2010

Вы не хотите делать это с макросами в 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;
}

Аналогично, квадрат должен быть функцией:

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

(Хотя на практике квадрат не очень полезен, вы бы просто умножили напрямую.)


В качестве любопытства, хотя я бы не рекомендовал его в этом случае (вышеуказанная функция подходит), шаблонный эквивалент метапрограммирования будет:

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.

1 голос
/ 11 марта 2010

Я видел это ...

#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, оно преобразуется в 3, а затем передается в STRING_A_NUMBER_I, это немного уклоняет, кто-нибудь может уточнить?

1 голос
/ 11 марта 2010
Директива препроцессора

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

кажется более разумным и более эффективным.

Редактировать : согласно предложению Криса Латца, второй макрос автоматически подстраивается под определение xsof; по меткам, на основе подсчета 1.

0 голосов
/ 11 марта 2010

Вы не можете превратить целые числа в строки, поэтому 1 ---> "One", 2 ---> "Two" и т. Д., Кроме перечисления каждого значения.

Вы можете преобразовать значение аргумента в строку с препроцессором 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 .

...