Proste pytanie, na które nie mogłem znaleźć odpowiedzi w sieci. Jak znaleźć liczbę argumentów w makrach argumentów o zmiennej liczbie argumentów? Jestem w porządku z preprocesorem doładowania, jeśli ma rozwiązanie.
Jeśli to robi różnicę, próbuję przekonwertować zmienną liczbę argumentów makr, aby zwiększyć sekwencję, listę lub tablicę preprocesora w celu dalszego przetwarzania.
c++
c
c-preprocessor
variadic-macros
Anycorn
źródło
źródło
__typeof__
, aby działał przynajmniej na niektórych kompilatorachOdpowiedzi:
W rzeczywistości jest to zależne od kompilatora i nie jest obsługiwane przez żaden standard.
Tutaj jednak masz implementację makra , która liczy:
źródło
#define EXPAND(x) x
#define PP_ARG_N(_1,_2,_3,_4,_5,_6,_7,_8,_9,N,...) N
#define PP_NARG(...) EXPAND(PP_ARG_N(__VA_ARGS__, 9,8,7,6,5,4,3,2,1,0))
``PP_NARG()
nie zwraca 0. RozwiązaniaGET_ARG_COUNT()
&Y_TUPLE_SIZE()
działają.PP_NARG()
nie zwraca 0” ... niekoniecznie stanowi problem. Można powiedzieć, żePP_NARG()
powinno zwrócić 1 z tego samego powodu,PP_NARG(,)
powinno zwrócić 2. Wykrywanie 0 może być rzeczywiście przydatne w niektórych przypadkach, ale rozwiązania wydają się albo mniej ogólne (wymaganie, aby pierwszy token był możliwy do wklejenia; co może być lub nie być w porządku w zależności od tego, do czego go używasz) lub specyficzne dla implementacji (na przykład wymaganie sztuczki gnu z usuwaniem przecinków i wklejaniem).Zwykle używam tego makra, aby znaleźć kilka parametrów:
Pełny przykład:
Jest to całkowicie poprawny kod C99. Ma jednak jedną wadę - nie można wywołać makra
SUM()
bez parametrów, ale GCC ma na to rozwiązanie - patrz tutaj .Więc w przypadku GCC musisz zdefiniować makra w ten sposób:
i będzie działać nawet z pustą listą parametrów
źródło
sizeof(int) != sizeof(void *)
?{__VA_ARGS__}
naint[]
, to jest po prostuint[]
, niezależnie od faktycznej treści__VA_ARGS__
##
jest potrzebny w VS2017, ponieważ pusty__VA_ARGS__
automatycznie usunie poprzedni przecinek.Jeśli używasz C ++ 11 i potrzebujesz wartości jako stałej C ++ czasu kompilacji, bardzo eleganckim rozwiązaniem jest:
Uwaga: liczenie odbywa się w całości w czasie kompilacji, a wartość może być używana zawsze, gdy wymagana jest liczba całkowita w czasie kompilacji, na przykład jako parametr szablonu w std :: array.
źródło
sizeof((int[]){__VA_ARGS__})/sizeof(int)
powyższego, działa nawet wtedy, gdy nie można przesłać wszystkich argumentówint
.#define NUM_ARGS(...) std::tuple_size<decltype(std::make_tuple(__VA_ARGS__))>::value
Dla wygody, oto implementacja, która działa dla 0 do 70 argumentów i działa w Visual Studio, GCC i Clang . Wierzę, że będzie działać w Visual Studio 2010 i nowszych, ale przetestowałem go tylko w VS2013.
źródło
__VA_ARGS__
” (która w C ++ jest technicznie (prawie uniwersalnym, de facto standardowym) rozszerzeniem kompilatora aż do C ++ 20). Większość (wszystkich?) Kompilatorów dopuszcza zerową długość, ale dławi się na końcowym przecinku, jeśli lista jest pusta (i przeciąża##
jako protokół__VA_OPT__
, aby usunąć przecinek w tym przypadku); Wersja msvc za przedłużenia prostu nie zadławić przecinkiem (ale będzie dusić na przeciążony##
). Porównaj MSVCunused, __VA_ARGS__
do nieprzestrzegania MSVC0, ## __VA_ARGS__
; żadne nie jest bardziej poprawne, problem polega na tym, że są różne.Istnieje kilka rozwiązań C ++ 11 do znajdowania liczby argumentów w czasie kompilacji, ale jestem zaskoczony, widząc, że nikt nie zasugerował czegoś tak prostego, jak:
To również nie wymaga włączenia
<tuple>
nagłówka.źródło
VA_COUNT(&,^,%)
. Ponadto, jeśli liczysz przez funkcję, nie widzę sensu w tworzeniu makra.działa to z 0 argumentami z gcc / llvm. [linki są głupie]
Wydaje się, że program Visual Studio ignoruje operator ## używany do zużywania pustego argumentu. Prawdopodobnie możesz to obejść za pomocą czegoś takiego
źródło
##__VA_ARGS__
zjadanie przecinka przed if__VA_ARGS__
jest puste to rozszerzenie GCC. To nie jest standardowe zachowanie.Z rozszerzeniem msvc:
Działa dla 0 - 32 argumentów. Limit ten można łatwo rozszerzyć.
EDYCJA: Uproszczona wersja (działa w VS2015 14.0.25431.01 Update 3 i gcc 7.4.0) do 100 argumentów do kopiowania i wklejania:
źródło
Y_TUPLE_SIZE("Hello")
, co sprawia, że jest to całkiem niewykonalne. Zgadzam się z @osirisgothra.Zakładam, że każdy argument do VA_ARGS będzie oddzielony przecinkami. Jeśli tak, myślę, że powinno to działać jako całkiem czysty sposób na zrobienie tego.
Pracował dla mnie na godbolt dla Clang 4 i GCC 5.1. Spowoduje to obliczenie w czasie kompilacji, ale nie zostanie oszacowane dla preprocesora. Więc jeśli próbujesz zrobić coś takiego jak tworzenie FOR_EACH , to nie zadziała.
źródło
NUMARGS(hello, world = 2, ohmy42, !@#$%^&*()-+=)
!!! Każdy łańcuch argumentu nie może mieć innych symboli, jak','
chociażbyint count = NUMARGS( foo(1, 2) );
tutaj prosty sposób na policzenie 0 lub więcej argumentów VA_ARGS , mój przykład zakłada maksymalnie 5 zmiennych, ale możesz dodać więcej, jeśli chcesz.
źródło
VA_ARGS_NUM
jest używane z makrem: jeśli mam#define TEST
(tj. PusteTEST
) iVA_ARGS_NUM(TEST)
nie zwraca 0 (zero), gdy jest używane w#if
:(Możesz ciągnąć i liczyć tokeny:
źródło
Boost Preprocessor faktycznie ma to od Boost 1.49, as
BOOST_PP_VARIADIC_SIZE(...)
. Działa do rozmiaru 64.Pod maską to w zasadzie to samo, co odpowiedź Kornela Kisielewicza .
źródło
__VA_OPT__
lub rozszerzeń kompilatora do##__VA_ARGS__
usunięcia poprzedniego przecinka, np .: godbolt.org/z/X7OvnKZnalazłem tutaj odpowiedzi wciąż niekompletne.
Najbardziej najbliższa przenośna implementacja, jaką tutaj znalazłem, to: preprocesor C ++ __VA_ARGS__ liczba argumentów
Ale to nie działa z zerowymi argumentami w GCC bez przynajmniej
-std=gnu++11
parametru wiersza poleceń.Postanowiłem więc połączyć to rozwiązanie z tym: https://gustedt.wordpress.com/2010/06/08/detect-empty-macro-arguments/
https://godbolt.org/z/3idaKd
c++11
,msvc 2015
,gcc 4.7.1
,clang 3.0
źródło