Być może przeciążenia funkcji, parametry domyślne, szablony wariadyczne lub ewentualnie nazwany idiom parametrów są tym, czego szukasz
smoothware
Proszę zaktualizuj wybraną odpowiedź do tych, które uzyskały wysokie głosy, podając rzeczywiste rozwiązania, a nie te, które miały niskie głosy, mówiącNo you can't
Albert Renshaw
Odpowiedzi:
158
Oto jeden sposób, aby to zrobić. Używa listy argumentów dwukrotnie, najpierw do utworzenia nazwy makra pomocnika, a następnie do przekazania argumentów do tego makra pomocniczego. Używa standardowej sztuczki, aby policzyć liczbę argumentów do makra.
To całkiem fajne, ale nie sądzę, żeby zadziałało, gdybym właśnie wykonał PRINT_STRING. W takim przypadku nie byłoby domyślnego wydruku (i tak właśnie jest w przypadku, którego chcę użyć). Wciąż +1 za naprawdę fajne.
Cenoc
2
działa dla mnie w gcc (i jest bardzo sprytne!) :-), ale nie działa dla mnie w Visual Studio :-(
Tim Gradwell
4
@TimGradwell - jest to spowodowane błędem w kompilatorze MSVC, który potwierdzili, ale nie naprawili go od prawie dekady. Jednak dostępne są obejścia .
BeeOnRope
Sprytne, ale nie działa dla opcjonalnych zmiennych argumentów makr z powodu „wypchnięcia” rzeczy, które masz w „GET_4th_ARG”.
Searchengine
czy to w PRINT_STRING_MACRO_CHOOSERogóle potrzebne? Czy mogę bezpośrednio zastąpić jego wewnętrznym ciałem i nazwać to wszystko (__VA_ARGS__)?
Herrgott
85
Z wielkim szacunkiem dla Dereka Ledbettera za jego odpowiedź - i z przeprosinami za przywrócenie starego pytania.
Zrozumienie tego, co robił, i zebranie w innym miejscu zdolności poprzedzającej __VA_ARGS__z, ##pozwoliło mi wymyślić odmianę ...
// The multiple macros that you would need anyway [as per: Crazy Eddie]#define XXX_0()<code for no arguments>#define XXX_1(A)<code for one argument>#define XXX_2(A,B)<code for two arguments>#define XXX_3(A,B,C)<code for three arguments>#define XXX_4(A,B,C,D)<code for four arguments>// The interim macro that simply strips the excess and ends up with the required macro#define XXX_X(x,A,B,C,D,FUNC,...) FUNC
// The macro that the programmer uses #define XXX(...) XXX_X(,##__VA_ARGS__,\
XXX_4(__VA_ARGS__),\
XXX_3(__VA_ARGS__),\
XXX_2(__VA_ARGS__),\
XXX_1(__VA_ARGS__),\
XXX_0(__VA_ARGS__)\
)
Dla nie-ekspertów takich jak ja, którzy natkną się na odpowiedź, ale nie do końca rozumieją, jak to działa, przejdę przez rzeczywiste przetwarzanie, zaczynając od następującego kodu ...
XXX();
XXX(1);
XXX(1,2);
XXX(1,2,3);
XXX(1,2,3,4);
XXX(1,2,3,4,5);// Not actually valid, but included to show the process
Możesz otrzymać wyraźny błąd kompilacji, jeśli przekonwertowałeś wybrany argument, który ma być nazwą MAKRO na łańcuch za pomocą # (znak krzyżyka) i porównałeś jego pierwsze n znaków z oczekiwanym przedrostkiem, a jeśli nie ma dopasowania, wypisano informacyjny błąd.
AturSams,
1
Wow, nie wiem, czy to działa, ale jest przynajmniej bardzo kreatywne!
Limited Atonement
4
dlaczego pierwszy argument jest zawsze pusty? dlaczego nie możemy tego po prostu pominąć: XXX_X(,##__VA_ARGS__,` ... XXX_X (, XXX_4 (), XXX_3 (), XXX_2 (), XXX_1 (), XXX_0 ()); `
rahman
2
Ważny jest pusty pierwszy argument (przecinek). ## __ VA_ARGS__, jeśli jest poprzedzony przecinkiem - usuwa przecinek, jeśli ## __ VA_ARGS__ rozwinie się do zera. Możesz to zobaczyć w przykładzie "Staje się ...", ponieważ pierwsza linia (bez argumentów) ma tylko 6 parametrów, ale reszta otrzymuje 7. Ta sztuczka zapewnia, że sytuacja bez argumentów działa
David Sorkovsky
@Eric - jest to spowodowane błędem w kompilatorach Microsoft, ale możesz zobaczyć to pytanie w celu obejścia problemu.
BeeOnRope
31
Makra C ++ nie zmieniły się od C. Ponieważ C nie ma przeciążenia i domyślnych argumentów funkcji, z pewnością nie ma ich dla makr. Odpowiadając na pytanie: nie, te funkcje nie istnieją w przypadku makr. Jedyną opcją jest zdefiniowanie wielu makr o różnych nazwach (lub nieużywanie makr w ogóle).
Na marginesie: w C ++ za dobrą praktykę uważa się jak największe odejście od makr. Jeśli potrzebujesz takich funkcji, istnieje duża szansa, że nadużywasz makr.
Zwróć uwagę, że powodem, dla którego niemożliwe jest „przeciążenie” makr, jest to, że nie mają one żadnych typów. Makra są po prostu rozwijane.
mk12,
2
Mimo, że korzystać z makr w jak najmniejszym stopniu, stwierdziliśmy, że debugowanie poprzez wyjście śledzenia dostaje trochę łatwiej z rzeczy, jak __FILE__i __LINE__i takie ...
Kompilacja warunkowa i debugowanie / rejestrowanie to domena, w której makra są naprawdę przydatne i legalne. Wie o tym każdy poważny programista. Dobrą praktyką jest unikanie używania makr do definiowania stałych i robienie zwariowanych czynności związanych z kodowaniem na poziomie C w celu tworzenia szablonów kontenerów. Chciałbym, żeby C ++ dodał więcej funkcji do makr. Są prostopadłe do szablonów. Oczywiście najlepsze byłyby kodele, które pozwalają mi dodawać generatory do kompilatora dla języka specyficznego dla domeny (aspekty).
Lothar
1
Myślę też, że to nie jest dobra odpowiedź, ponieważ makro jest czymś zupełnie innym niż jakakolwiek opcja języka C ++, ponieważ zostanie obsłużona PRZED kompilatorem. Możesz więc robić inne rzeczy i żaden kompilator ani konsolidator nie musi optymalizować kodu, ponieważ być może nie jest to optymalizacja.
alabamajack
26
Z wielkim szacunkiem dla Dereka Ledbettera , Davida Sorkovsky'ego , Syphorlate za ich odpowiedzi, wraz z genialną metodą wykrywania pustych argumentów makro Jensa Gustedta w
w końcu wyszedłem z czymś, co zawiera wszystkie sztuczki, tak że rozwiązanie
Używa tylko standardowych makr C99, aby osiągnąć przeciążenie funkcji, bez rozszerzenia GCC / CLANG / MSVC (tj. Połykanie przecinków przez określone wyrażenie , ##__VA_ARGS__dla GCC / CLANG i niejawne połykanie przez ##__VA_ARGS__dla MSVC). Więc --std=c99jeśli chcesz, możesz przekazać brakujące informacje do swojego kompilatora =)
Działa dla zerowych argumentów , a także dla nieograniczonej liczby argumentów , jeśli rozszerzysz je dalej, aby dopasować je do swoich potrzeb
Działa rozsądnie na wielu platformach , przynajmniej przetestowany pod kątem
GNU / Linux + GCC (GCC 4.9.2 na CentOS 7.0 x86_64)
GNU / Linux + CLANG / LLVM , (CLANG / LLVM 3.5.0 na CentOS 7.0 x86_64)
OS X + Xcode (XCode 6.1.1 w systemie OS X Yosemite 10.10.1)
Windows + Visual Studio (Visual Studio 2013 Update 4 w systemie Windows 7 SP1 64 bity)
Dla leniwców po prostu przejdź do ostatniego z tego postu, aby skopiować źródło. Poniżej znajduje się szczegółowe wyjaśnienie, które, miejmy nadzieję, pomoże i zainspiruje wszystkich szukających generała__VA_ARGS__ rozwiązań, takich jak ja. =)
Oto jak to działa. Najpierw zdefiniować przeciążony „funkcja” widoczne dla użytkowników, nazwałem go create, a związane rzeczywista definicja funkcji realCreate, a makro definicje z różną liczbą argumentów CREATE_2, CREATE_1, CREATE_0, jak pokazano poniżej:
MACRO_CHOOSER(__VA_ARGS__)Część ostatecznie postanawia makro nazwy definicji, a druga (__VA_ARGS__)część obejmuje swoje listy parametrów. Tak więc wywołanie użytkownika do jest create(10)rozstrzygane na CREATE_1(10), CREATE_1część pochodzi z MACRO_CHOOSER(__VA_ARGS__), a(10) część z drugiej (__VA_ARGS__).
MACRO_CHOOSERStosuje podstęp, że jeśli __VA_ARGS__jest pusta, następujące wyrażenie jest łączony do ważnej rozmowy przez makro preprocesora:
NO_ARG_EXPANDER __VA_ARGS__ ()// simply shrinks to NO_ARG_EXPANDER()
Genialnie możemy zdefiniować to wynikowe wywołanie makra jako
#define NO_ARG_EXPANDER(),,CREATE_0
Zwróć uwagę na dwa przecinki, zostaną one wkrótce wyjaśnione. Kolejne przydatne makro to
Jak sugeruje nazwa makra, później policzymy liczbę argumentów. Oto kolejna sztuczka: preprocesor wykonuje tylko prostą zamianę tekstu. Wyprowadza liczbę argumentów wywołania makra jedynie z liczby przecinków, które widzi w nawiasach. Rzeczywiste „argumenty” oddzielone przecinkami nie muszą mieć prawidłowej składni. Może to być dowolny tekst. To znaczy, że w powyższym przykładzie NO_ARG_EXPANDER 10 ()jest liczony jako 1 argument dla wywołania środkowego.NO_ARG_EXPANDER 20i 20 ()są liczone jako 2 argumenty odpowiednio dla dolnego wywołania.
Jeśli użyjemy następujących makr pomocniczych, aby je dalej rozwinąć
Końcowe ,po CREATE_1jest obejściem dla GCC / CLANG, pomijając (fałszywie dodatni) błąd mówiący o tym ISO C99 requires rest arguments to be usedpodczas przekazywania -pedanticdo kompilatora. Jest FUNC_RECOMPOSERto obejście dla MSVC lub nie może poprawnie policzyć liczby argumentów (tj. Przecinków) w nawiasach przy wywołaniach makr. Wyniki są dalej rozwiązywane do
Jak zapewne widzieliście orle oczy, ostatnim jedynym krokiem, jakiego potrzebujemy, jest zastosowanie standardowej sztuczki zliczania argumentów, aby ostatecznie wybrać żądane nazwy wersji makr:
#define FUNC_CHOOSER(_f1, _f2, _f3,...) _f3
który rozwiązuje wyniki na
CREATE_0();
CREATE_1(10);
CREATE_2(20,20);
i na pewno daje nam pożądane, rzeczywiste wywołania funkcji:
Chociaż jest to skomplikowane, brzydkie, obciążające programistę API, pojawia się rozwiązanie do przeciążania i ustawiania opcjonalnych parametrów funkcji C / C ++ dla nas szalonych ludzi. Korzystanie z wychodzących przeciążonych interfejsów API staje się bardzo przyjemne i przyjemne. =)
Jeśli istnieje jakiekolwiek dalsze uproszczenie tego podejścia, proszę o kontakt pod adresem
Dla każdego, kto szuka rozwiązania VA_NARGS, które współpracuje z Visual C ++. Poniższe makro działało dla mnie bezbłędnie (również bez parametrów!) W Visual C ++ Express 2010:
#define VA_NUM_ARGS_IMPL(_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_14,_15,_16,_17,_18,_19,_20,_21,_22,_23,_24,N,...) N
#define VA_NUM_ARGS_IMPL_(tuple) VA_NUM_ARGS_IMPL tuple
#define VA_NARGS(...)bool(#__VA_ARGS__)?(VA_NUM_ARGS_IMPL_((__VA_ARGS__,24,23,22,21,20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1))):0
Jeśli chcesz mieć makro z opcjonalnymi parametrami, możesz zrobić:
Dostajęunresolved external symbol _bool referenced in function _main
Avidan Borisov
tak, może się to zdarzyć w niektórych przypadkach. musisz wiedzieć, że bool (#__ VA_ARGS__)? różni się od innych makr, ponieważ jest oceniany w czasie wykonywania. w zależności od przypadku możesz jednak pominąć tę część kodu.
Dzięki za link i tak, możesz to zrobić również za pomocą sizeof, ale dla mnie to nie działało w niektórych przypadkach, ale zasada jest taka sama (ocena logiczna).
Syphorlate
Czy mógłbyś podać kilka przykładów, w których się to nie udaje?
Avidan Borisov
7
gcc/ g++obsługuje makra varargs, ale nie sądzę, aby to było standardowe, więc używaj go na własne ryzyko.
Są standardowe w C99 i są również dodawane do C ++ 0x.
greyfade
5
#include<stdio.h>#define PP_NARG(...) \
PP_NARG_(__VA_ARGS__,PP_RSEQ_N())#define PP_NARG_(...) \
PP_ARG_N(__VA_ARGS__)#define PP_ARG_N( \
_1, _2, _3, _4, _5, _6, _7, _8, _9,_10, \
_11,_12,_13,_14,_15,_16,_17,_18,_19,_20, \
_21,_22,_23,_24,_25,_26,_27,_28,_29,_30, \
_31,_32,_33,_34,_35,_36,_37,_38,_39,_40, \
_41,_42,_43,_44,_45,_46,_47,_48,_49,_50, \
_51,_52,_53,_54,_55,_56,_57,_58,_59,_60, \
_61,_62,_63,N,...) N
#define PP_RSEQ_N() \
63,62,61,60, \
59,58,57,56,55,54,53,52,51,50, \
49,48,47,46,45,44,43,42,41,40, \
39,38,37,36,35,34,33,32,31,30, \
29,28,27,26,25,24,23,22,21,20, \
19,18,17,16,15,14,13,12,11,10, \
9,8,7,6,5,4,3,2,1,0#define PP_CONCAT(a,b) PP_CONCAT_(a,b)#define PP_CONCAT_(a,b) a ## b#define THINK(...) PP_CONCAT(THINK_, PP_NARG(__VA_ARGS__))(__VA_ARGS__)#define THINK_0() THINK_1("sector zz9 plural z alpha")#define THINK_1(location) THINK_2(location,42)#define THINK_2(location,answer) THINK_3(location, answer,"deep thought")#define THINK_3(location,answer,computer) \
printf ("The answer is %d. This was calculated by %s, and a computer to figure out what this"" actually means will be build in %s\n",(answer),(computer),(location))int
main (int argc,char*argv[]){
THINK ();/* On compilers other than GCC you have to call with least one non-default argument */}
w twoim kodzie jest błąd. proszę :%s/MY_MACRO_/THINK_/g:)
João Portela
również nie działało z zerowymi argumentami przy użyciu g ++i686-apple-darwin10-g++-4.2.1 (GCC) 4.2.1 (Apple Inc. build 5664)
João Portela.
1
Zero argumentów nie istnieje dla makr variadiac, ponieważ pusty token jest prawidłowym symbolem zastępczym.
Paul Fultz II,
3
Nie do tego jest przeznaczony preprocesor.
To powiedziawszy, jeśli chcesz wejść w obszar poważnie trudnego programowania makr z odrobiną czytelności, powinieneś przyjrzeć się bibliotece preprocesorów Boost . W końcu nie byłoby C ++, gdyby nie było trzech poziomów programowania całkowicie zgodnych z Turingiem (preprocesor, metaprogramowanie szablonów i podstawowy poziom C ++)!
Jako wielki fan okropnych potworów makro, chciałem rozwinąć odpowiedź Jasona Denga i uczynić ją użyteczną. (Na lepsze lub gorsze.) Oryginał nie jest zbyt przyjemny w użyciu, ponieważ za każdym razem, gdy chcesz zrobić nowe makro, musisz modyfikować zupę z dużym alfabetem, a jest jeszcze gorzej, jeśli potrzebujesz innej ilości argumentów.
Zrobiłem więc wersję z następującymi funkcjami:
0 argumentów działa
Od 1 do 16 argumentów bez żadnych modyfikacji w niechlujnej części
Łatwo napisać więcej funkcji makr
Testowane w GCC 10, Clang 9, Visual Studio 2017
Obecnie zrobiłem maksymalnie 16 argumentów, ale jeśli potrzebujesz więcej (naprawdę teraz? Po prostu robisz się głupi ...) możesz edytować FUNC_CHOOSER i CHOOSE_FROM_ARG_COUNT, a następnie dodać przecinki do NO_ARG_EXPANDER.
Zobacz doskonałą odpowiedź Jasona Denga, aby uzyskać więcej informacji na temat implementacji, ale wstawię kod tutaj:
#include<stdio.h>void realCreate(int x,int y){
printf("(%d, %d)\n", x, y);}// This part you put in some library header:#define FUNC_CHOOSER(_f0, _f1, _f2, _f3, _f4, _f5, _f6, _f7, _f8, _f9, _f10, _f11, _f12, _f13, _f14, _f15, _f16,...) _f16
#define FUNC_RECOMPOSER(argsWithParentheses) FUNC_CHOOSER argsWithParentheses
#define CHOOSE_FROM_ARG_COUNT(F,...) FUNC_RECOMPOSER((__VA_ARGS__, \
F##_16, F##_15, F##_14, F##_13, F##_12, F##_11, F##_10, F##_9, F##_8,\
F##_7, F##_6, F##_5, F##_4, F##_3, F##_2, F##_1, ))#define NO_ARG_EXPANDER(FUNC),,,,,,,,,,,,,,,,FUNC ## _0#define MACRO_CHOOSER(FUNC,...) CHOOSE_FROM_ARG_COUNT(FUNC, NO_ARG_EXPANDER __VA_ARGS__ (FUNC))#define MULTI_MACRO(FUNC,...) MACRO_CHOOSER(FUNC, __VA_ARGS__)(__VA_ARGS__)// When you need to make a macro with default arguments, use this:#define create(...) MULTI_MACRO(CREATE, __VA_ARGS__)#define CREATE_0() CREATE_1(0)#define CREATE_1(x) CREATE_2(x,0)#define CREATE_2(x, y) \
do{ \
/* put whatever code you want in the last macro */ \
realCreate(x, y); \
}while(0)int main(){
create();
create(10);
create(20,20);//create(30, 30, 30); // Compilation errorreturn0;}
W zależności od tego, czego potrzebujesz, możesz to zrobić za pomocą argumentów var z makrami. Otóż, opcjonalne parametry czy przeciążenie makr, nie ma czegoś takiego.
Żaden z powyższych przykładów (od Dereka Ledbettera, Davida Sorkovsky'ego i Joe D) do liczenia argumentów z makrami nie działał dla mnie przy użyciu Microsoft VCC 10. __VA_ARGS__Argument jest zawsze traktowany jako pojedynczy argument (tokenizowanie go z ##lub nie), więc przesunięcie argumentów, na którym polegają te przykłady, nie działa.
Krótka odpowiedź, jak twierdzi wielu innych powyżej: nie, nie można przeciążać makr ani używać w nich opcjonalnych argumentów.
Możesz, ale tylko w C99 lub C ++ 11 (ze względu na posiadanie __VA_ARGS__). VC2010 to C89 / C ++ 03 (z niektórymi bitami C ++ 11 zaczynają się pojawiać, ale jeszcze nie ten).
No you can't
Odpowiedzi:
Oto jeden sposób, aby to zrobić. Używa listy argumentów dwukrotnie, najpierw do utworzenia nazwy makra pomocnika, a następnie do przekazania argumentów do tego makra pomocniczego. Używa standardowej sztuczki, aby policzyć liczbę argumentów do makra.
Ułatwia to wywołującemu makro, ale nie piszącemu.
źródło
PRINT_STRING_MACRO_CHOOSER
ogóle potrzebne? Czy mogę bezpośrednio zastąpić jego wewnętrznym ciałem i nazwać to wszystko(__VA_ARGS__)
?Z wielkim szacunkiem dla Dereka Ledbettera za jego odpowiedź - i z przeprosinami za przywrócenie starego pytania.
Zrozumienie tego, co robił, i zebranie w innym miejscu zdolności poprzedzającej
__VA_ARGS__
z,##
pozwoliło mi wymyślić odmianę ...Dla nie-ekspertów takich jak ja, którzy natkną się na odpowiedź, ale nie do końca rozumieją, jak to działa, przejdę przez rzeczywiste przetwarzanie, zaczynając od następującego kodu ...
Staje się...
Co staje się dopiero szóstym argumentem ...
PS: Usuń #define dla XXX_0, aby uzyskać błąd kompilacji [tj .: jeśli opcja bez argumentów jest niedozwolona].
PPS: Byłoby miło, gdyby nieprawidłowe sytuacje (np .: 5) były czymś, co daje programiście wyraźniejszy błąd kompilacji!
PPPS: Nie jestem ekspertem, więc bardzo się cieszę, słysząc komentarze (dobre, złe lub inne)!
źródło
XXX_X(,##__VA_ARGS__,` ...
XXX_X (, XXX_4 (), XXX_3 (), XXX_2 (), XXX_1 (), XXX_0 ()); `Makra C ++ nie zmieniły się od C. Ponieważ C nie ma przeciążenia i domyślnych argumentów funkcji, z pewnością nie ma ich dla makr. Odpowiadając na pytanie: nie, te funkcje nie istnieją w przypadku makr. Jedyną opcją jest zdefiniowanie wielu makr o różnych nazwach (lub nieużywanie makr w ogóle).
Na marginesie: w C ++ za dobrą praktykę uważa się jak największe odejście od makr. Jeśli potrzebujesz takich funkcji, istnieje duża szansa, że nadużywasz makr.
źródło
__FILE__
i__LINE__
i takie ...Z wielkim szacunkiem dla Dereka Ledbettera , Davida Sorkovsky'ego , Syphorlate za ich odpowiedzi, wraz z genialną metodą wykrywania pustych argumentów makro Jensa Gustedta w
https://gustedt.wordpress.com/2010/06/08/detect-empty-macro-arguments/
w końcu wyszedłem z czymś, co zawiera wszystkie sztuczki, tak że rozwiązanie
, ##__VA_ARGS__
dla GCC / CLANG i niejawne połykanie przez##__VA_ARGS__
dla MSVC). Więc--std=c99
jeśli chcesz, możesz przekazać brakujące informacje do swojego kompilatora =)Działa rozsądnie na wielu platformach , przynajmniej przetestowany pod kątem
Dla leniwców po prostu przejdź do ostatniego z tego postu, aby skopiować źródło. Poniżej znajduje się szczegółowe wyjaśnienie, które, miejmy nadzieję, pomoże i zainspiruje wszystkich szukających generała
__VA_ARGS__
rozwiązań, takich jak ja. =)Oto jak to działa. Najpierw zdefiniować przeciążony „funkcja” widoczne dla użytkowników, nazwałem go
create
, a związane rzeczywista definicja funkcjirealCreate
, a makro definicje z różną liczbą argumentówCREATE_2
,CREATE_1
,CREATE_0
, jak pokazano poniżej:MACRO_CHOOSER(__VA_ARGS__)
Część ostatecznie postanawia makro nazwy definicji, a druga(__VA_ARGS__)
część obejmuje swoje listy parametrów. Tak więc wywołanie użytkownika do jestcreate(10)
rozstrzygane naCREATE_1(10)
,CREATE_1
część pochodzi zMACRO_CHOOSER(__VA_ARGS__)
, a(10)
część z drugiej(__VA_ARGS__)
.MACRO_CHOOSER
Stosuje podstęp, że jeśli__VA_ARGS__
jest pusta, następujące wyrażenie jest łączony do ważnej rozmowy przez makro preprocesora:Genialnie możemy zdefiniować to wynikowe wywołanie makra jako
Zwróć uwagę na dwa przecinki, zostaną one wkrótce wyjaśnione. Kolejne przydatne makro to
więc wezwania
są faktycznie rozszerzone do
Jak sugeruje nazwa makra, później policzymy liczbę argumentów. Oto kolejna sztuczka: preprocesor wykonuje tylko prostą zamianę tekstu. Wyprowadza liczbę argumentów wywołania makra jedynie z liczby przecinków, które widzi w nawiasach. Rzeczywiste „argumenty” oddzielone przecinkami nie muszą mieć prawidłowej składni. Może to być dowolny tekst. To znaczy, że w powyższym przykładzie
NO_ARG_EXPANDER 10 ()
jest liczony jako 1 argument dla wywołania środkowego.NO_ARG_EXPANDER 20
i20 ()
są liczone jako 2 argumenty odpowiednio dla dolnego wywołania.Jeśli użyjemy następujących makr pomocniczych, aby je dalej rozwinąć
Końcowe
,
poCREATE_1
jest obejściem dla GCC / CLANG, pomijając (fałszywie dodatni) błąd mówiący o tymISO C99 requires rest arguments to be used
podczas przekazywania-pedantic
do kompilatora. JestFUNC_RECOMPOSER
to obejście dla MSVC lub nie może poprawnie policzyć liczby argumentów (tj. Przecinków) w nawiasach przy wywołaniach makr. Wyniki są dalej rozwiązywane doJak zapewne widzieliście orle oczy, ostatnim jedynym krokiem, jakiego potrzebujemy, jest zastosowanie standardowej sztuczki zliczania argumentów, aby ostatecznie wybrać żądane nazwy wersji makr:
który rozwiązuje wyniki na
i na pewno daje nam pożądane, rzeczywiste wywołania funkcji:
Podsumowując wszystko razem, z pewnym przegrupowaniem instrukcji dla lepszej czytelności, całe źródło dwuargumentowego przykładu jest tutaj:
Chociaż jest to skomplikowane, brzydkie, obciążające programistę API, pojawia się rozwiązanie do przeciążania i ustawiania opcjonalnych parametrów funkcji C / C ++ dla nas szalonych ludzi. Korzystanie z wychodzących przeciążonych interfejsów API staje się bardzo przyjemne i przyjemne. =)
Jeśli istnieje jakiekolwiek dalsze uproszczenie tego podejścia, proszę o kontakt pod adresem
https://github.com/jason-deng/C99FunctionOverload
Jeszcze raz specjalne podziękowania dla wszystkich wspaniałych ludzi, którzy zainspirowali mnie i doprowadzili do wykonania tego dzieła! =)
źródło
Dla każdego, kto szuka rozwiązania VA_NARGS, które współpracuje z Visual C ++. Poniższe makro działało dla mnie bezbłędnie (również bez parametrów!) W Visual C ++ Express 2010:
Jeśli chcesz mieć makro z opcjonalnymi parametrami, możesz zrobić:
To zadziałało również dla mnie w vc. Ale to nie działa dla zerowych parametrów.
źródło
unresolved external symbol _bool referenced in function _main
gcc
/g++
obsługuje makra varargs, ale nie sądzę, aby to było standardowe, więc używaj go na własne ryzyko.źródło
ZASTRZEŻENIE: W większości nieszkodliwe.
źródło
:%s/MY_MACRO_/THINK_/g
:)i686-apple-darwin10-g++-4.2.1 (GCC) 4.2.1 (Apple Inc. build 5664)
Nie do tego jest przeznaczony preprocesor.
To powiedziawszy, jeśli chcesz wejść w obszar poważnie trudnego programowania makr z odrobiną czytelności, powinieneś przyjrzeć się bibliotece preprocesorów Boost . W końcu nie byłoby C ++, gdyby nie było trzech poziomów programowania całkowicie zgodnych z Turingiem (preprocesor, metaprogramowanie szablonów i podstawowy poziom C ++)!
źródło
W momencie wywołania wiesz, ile argumentów przekażesz, więc naprawdę nie ma potrzeby przeciążania.
źródło
Bardziej zwięzła wersja kodu Dereka Ledbettera:
źródło
Jako wielki fan okropnych potworów makro, chciałem rozwinąć odpowiedź Jasona Denga i uczynić ją użyteczną. (Na lepsze lub gorsze.) Oryginał nie jest zbyt przyjemny w użyciu, ponieważ za każdym razem, gdy chcesz zrobić nowe makro, musisz modyfikować zupę z dużym alfabetem, a jest jeszcze gorzej, jeśli potrzebujesz innej ilości argumentów.
Zrobiłem więc wersję z następującymi funkcjami:
Obecnie zrobiłem maksymalnie 16 argumentów, ale jeśli potrzebujesz więcej (naprawdę teraz? Po prostu robisz się głupi ...) możesz edytować FUNC_CHOOSER i CHOOSE_FROM_ARG_COUNT, a następnie dodać przecinki do NO_ARG_EXPANDER.
Zobacz doskonałą odpowiedź Jasona Denga, aby uzyskać więcej informacji na temat implementacji, ale wstawię kod tutaj:
źródło
Możesz użyć
BOOST_PP_OVERLOAD
zboost
biblioteki.Przykład z oficjalnego dokumentu doładowania :
źródło
W zależności od tego, czego potrzebujesz, możesz to zrobić za pomocą argumentów var z makrami. Otóż, opcjonalne parametry czy przeciążenie makr, nie ma czegoś takiego.
źródło
Żaden z powyższych przykładów (od Dereka Ledbettera, Davida Sorkovsky'ego i Joe D) do liczenia argumentów z makrami nie działał dla mnie przy użyciu Microsoft VCC 10.
__VA_ARGS__
Argument jest zawsze traktowany jako pojedynczy argument (tokenizowanie go z##
lub nie), więc przesunięcie argumentów, na którym polegają te przykłady, nie działa.Krótka odpowiedź, jak twierdzi wielu innych powyżej: nie, nie można przeciążać makr ani używać w nich opcjonalnych argumentów.
źródło