Макрос С++ "##" не работает после оператора "->"

У меня есть объект shared_ptr x, который имеет методы get и set следующим образом:

x->a_value();
x->set_a_value();
x->b_value();
x->set_b_value();

Когда я пытаюсь определить макрос:

#define MAC(type) \
  x->set_##type##_value(val);

MAC(a)

Он отлично работает, но когда я это делаю:

#define MAC(type) \
  x->##type##_value();

MAC(a)

он дает следующую ошибку компиляции: pasting formed '->a', an invalid preprocessing token

Ответы

Ответ 1

Препроцессор работает на "токенах" - любит имена и операторы.

Оператор ## создает новый токен, вставляя меньшие части вместе. В первом примере set_##type##_value становится set_a_value, который является допустимым токеном.

Во втором примере ->##type##_value станет ->a_value, что не является допустимым токеном препроцессора. Это должно быть два токена.

Если вы просто сделаете строку x->type##_value(); он должен работать. Вы получаете отдельные токены x, ->, a_value, (, ) и ; ,

Ответ 2

Что он говорит на олове: ->a - не один, действительный токен препроцессора: это два токена. Вам не нужно вставлять сюда.

#define MAC(type) \
  x->type##_value();

Ответ 3

Оператор токена (##) используется для объединения двух токенов в один действительный токен.

Когда вы пишете

x->##type##_value();
  • Первый обработанный токен равен x.

  • Следующий токен формируется путем объединения типа токена -> с type, поскольку type является a, результатом конкатенации является ->a, который должен быть действительным токеном, но не является.

Следовательно, вы получаете ошибку: pasting formed '->a', an invalid preprocessing token.

Чтобы исправить это, просто напишите

x->type##_value();

Сюда

  • Первый обработанный токен равен x.

  • Следующий обработанный токен ->.

  • Следующий токен формируется путем объединения type токена (который становится a) с маркером _value. Это дает значение a_value, которое является действительным токеном.

  • Следующий токен (.

  • Следующий токен ).

  • Последний токен ; ,