Rozwiązaniem w pytanie jest takie:
#define EXPAND(x) x
#define F(x, ...) X = x and VA_ARGS = __VA_ARGS__
#define G(...) EXPAND(F(__VA_ARGS__))
Chodzi o to, że biorąc pod uwagę istniejący zmiennej liczbie argumentów makro F()
:
#define F(x, ...) X = x and VA_ARGS = __VA_ARGS__
zamiast pisać żądany zmiennej liczbie argumentów otoki makro jak w tym przypadku, ...
#define G(...) F(__VA_ARGS__)
... piszesz G()
z użyciem dodatkowego makra EXPAND()
. Rzeczywista definicja F()
nie jest punktem, a w szczególności nie ma znaczenia dla tego przykładu, że makro ekspansja nie tworzy poprawnego kodu C. Jego celem jest wykazanie zachowania preprocesora w odniesieniu do argumentów makr. W szczególności pokazuje to, że chociaż MSVC rozszerza __VA_ARGS__
na pojedynczy token w makrze wariadowym, można go obejść wymuszając podwójne rozszerzenie.
Na przykład, zgodnie z definicją obejścia preprocesor najpierw rozszerza ...
G(1, 2, 3)
... do ...
EXPAND(F(1, 2, 3))
... gdzie 1, 2, 3
jest traktowany jako pojedynczy token. Tokenizacja nie ma już znaczenia, gdy preprocesor przeskanuje dodatkowe zamienniki, jednak widzi 1
, 2
, 3
jako oddzielne argumenty dla makra F()
i rozwija je zgodnie z życzeniem, aby wytworzyć argument dla makra EXPAND()
, który po prostu zamienia go na siebie.
Jeśli uważasz, że to działa dziwnie, ale wersja bez EXPAND()
nie działa (w MSVC), masz rację.
Myślę, że połączony wpis jest nieprawidłowy. Myślę, że właściwym rozwiązaniem jest 'G (...) F (EXPAND (__ VA_ARGS__))' – LPs
@LPs, też tak myślałem, ale spróbuj. –
@JohnBollinger Jestem zbyt Linux wewnątrz, aby umieścić moje ręce na MSVC :). Poważnie, nie mam MSVC, żeby to przetestować. Niech OP wypróbuje to. – LPs