#c
#c
Вопрос:
Можно ли написать макрос, который применяется ровно один раз, независимо от того, сколько раз он вложен?
// how to implement this properly?
#define FOO(x) hello(x) // incorrect, works only for 1 level of nesting
// desired use below
void hello(int x);
FOO(x); // expanded to "hello(x)"
FOO(FOO(x)); // also expanded to "hello(x)", not "hello(hello(x))"
FOO(FOO(FOO(x))); // also expanded to "hello(x)"
Существуют ли какие-либо альтернативы реализации FOO
, возможно, не как макрос, а какой-либо шаблон C , который может достичь того же эффекта?
Зачем мне это нужно?
Я пишу преобразования clang libTooling от источника к источнику, которые включают некоторые переменные, используемые в моей собственной оболочке. Например, у меня есть следующий фрагмент кода: a[3] = 5;
он преобразуется в hello(a)[3] = 5;
, а значение и поведение hello
контролируются мной. Однако, если у меня есть следующий фрагмент кода
#define A a[3]
A = 4;
A = 5;
A = 6;
затем из-за ограничений clang libTooling я должен добавить изменения в тело макроса следующим образом:
#define A hello(a)[3]
A = 4;
A = 5;
A = 6;
К сожалению, этого нелегко достичь, потому что шаблон сопоставляется 3 раза, и не очевидно, как их различать в общем случае, поэтому все заканчивается так:
#define A hello(hello(hello(a)))[3]
A = 4;
A = 5;
A = 6;
Это, очевидно, не то, что я хочу, поэтому я ищу обходные пути. Я надеюсь, что дизайн какого-нибудь подобного макроса FOO
может решить проблему с наименьшими усилиями.
Комментарии:
1. AFAIK, нет. Если вы хотите запустить что-то один раз, вам следует изучить
std::call_once
2. Зачем вам что-то подобное? Просто не вводите
FOO(FOO
.3. Пожалуйста, опишите, что вы пытаетесь сделать более подробно, с учетом контекста.
4. @KamilCuk Я добавил объяснение моего варианта использования для него.
5. Предварительная обработка — это облегченный инструмент для удобства, а не полноценный инструмент для программирования. Избегайте возиться с ним.
Ответ №1:
Вы можете перегрузить функцию по типу аргумента. С помощью специального типа вы можете просто переслать его, вызывая функцию только тогда, когда указаны фактические аргументы.
void hello(int x);
struct FOO_hello_called {};
FOO_hello_called FOO(int x) {
hello(x);
return {};
}
FOO_hello_called FOO(FOO_hello_called s) {
return s;
}
int main() {
int x = 1;
FOO(x); // calls "hello(x)"
FOO(FOO(x)); // calls "hello(x)" once
FOO(FOO(FOO(x))); // also calls "hello(x)" once
}