ãã€ãã®ããã«ããã¹ãŠã¯ãšã©ãŒããå§ãŸããŸããã
Java Native Interfaceã䜿çšããã®ã¯ãããåããŠã§ãC ++ããŒãã§ã¯Javaãªããžã§ã¯ããäœæãã颿°ãã©ããããŸããã ãã®é¢æ°
CallVoidMethod
ã¯å¯å€ãã€ãŸã
JNIç°å¢ãžã®ãã€ã³ã¿ãŒãäœæããããªããžã§ã¯ãã®åãžã®ãã€ã³ã¿ãŒãããã³åŒã³åºãããã¡ãœããïŒãã®å Žåã¯ã³ã³ã¹ãã©ã¯ã¿ãŒïŒã®èå¥åã«å ããŠãä»»æã®æ°ã®ä»ã®åŒæ°ãåããŸãã è«ççã§ãããªããªã ãããã®ä»ã®åŒæ°ã¯ãJavaåŽã®åŒã³åºãããã¡ãœããã«æž¡ãããŸããã¡ãœããã¯ãä»»æã®ã¿ã€ãã®ç°ãªãæ°ã®åŒæ°ã§ç°ãªãããšãã§ããŸãã
ãããã£ãŠãã©ãããŒå€æ°ãäœæããŸããã
CallVoidMethod
ä»»æã®æ°ã®åŒæ°ã
CallVoidMethod
䜿çšã
va_list
ããã®å Žåã¯ç°ãªãããã§ãã ã¯ããããã¯
va_list
éä¿¡ãããã®
CallVoidMethod
ã ãããŠãJVMã®å¹³å¡ãªã»ã°ã¡ã³ããŒã·ã§ã³ãšã©ãŒãåé€ããŸããã
2æéã§ã8æ¥ãã11æ¥ãŸã§ããã€ãã®ããŒãžã§ã³ã®JVMã詊ãããšãã§ããŸãããããã¯ãæåã¯ããã
JVMã®æåã®çµéšã§ããããã®åé¡ã§ã¯èªåãããStackOverflowãä¿¡é Œããæ¬¡ã«èª°ããStackOverflowã§ã¯ããã®å ŽåãOpenJDKã§ã¯ãªãOracleJDKã䜿çšãã8ã§ã¯ãªã10ã䜿çšããããã«ã¢ããã€ã¹ããŸããããããŠã倿°
CallVoidMethod
ã«å ããŠã
CallVoidMethod
ãä»ããŠä»»æã®æ°ã®åŒæ°ãåã
CallVoidMethod
ãããããšã«æåŸã«æ°ä»ã
va_list
ã
ãã®è©±ã§äžçªæ°ã«å
¥ããªãã£ãã®ã¯ãçç¥èšå·ïŒellipsisïŒãš
va_list
éãã«ããã«æ°ä»ããªãã£ãããš
va_list
ã ãããŠæ°ã¥ããã®ã§ãæ ¹æ¬çãªéããäœã§ããããèªåã§èª¬æã§ããŸããã§ããã ãã®ãããçç¥èšå·ã
va_list
ãããã³ïŒãŸã C ++ã«ã€ããŠè©±ããŠããããïŒå€æ°ãã³ãã¬ãŒããæ±ãå¿
èŠããããŸãã
æšæºã®çç¥èšå·ãšva_listã«ã€ããŠã®èª¬æ
C ++æšæºã§ã¯ããã®èŠä»¶ãšæšæºCã®èŠä»¶ãšã®éãã®ã¿ã説æããŠããŸããéãèªäœã«ã€ããŠã¯åŸã§èª¬æããŸãããããã§ã¯ãæšæºCã®å
容ïŒC89以éïŒã«ã€ããŠç°¡åã«èª¬æããŸãã
ãªãã§ïŒ ãããããªããªãïŒ
Cã«ã¯å€ãã®åã¯ãããŸããã æšæºã§
va_list
宣èšãããŠãã
va_list
ãå
éšæ§é ã«ã€ããŠã¯äœãè¿°ã¹ãããŠããªãã®ã¯ãªãã§ããïŒ
颿°ãžã®ä»»æã®æ°ã®åŒæ°ã
va_list
ãä»ããŠ
va_list
ããšãã§ããå Žåããªãçç¥èšå·ãå¿
èŠãªã®ã§ããïŒ ä»ã¯ãæ§æç³ãšããŠããšèšããŸããã40幎åã«ã¯ãç³ã®æéã¯ãªãã£ããšç¢ºä¿¡ããŠããŸãã
ãã£ãªãããžã§ãŒã ã¹ãã©ãŠã¬ãŒ
ãã£ãªãããžã§ãŒã ã¹ãã©ãŠã¬ãŒã¯ã
The Standard C library -1992-ã§ãæåã¯Cã¯PDP-11ã³ã³ãã¥ãŒã¿ãŒå°çšã«äœæããããšè¿°ã¹ãŠããŸãã ãŸããåçŽãªãã€ã³ã¿ãŒæŒç®ã䜿çšããŠã颿°ã®ãã¹ãŠã®åŒæ°ããœãŒãã§ããŸããã ãã®åé¡ã¯ãCã®äººæ°ãšä»ã®ã¢ãŒããã¯ãã£ãŒãžã®ã³ã³ãã€ã©ãŒã®è»¢éã§çºçããŸããã
ãã©ã€ã¢ã³ã»ã«ãŒãã¬ã³ãšããã¹ã»ãªãããŒ
ã«ããCããã°ã©ãã³ã°èšèªã®åç
-1978-ã«ã¯æ¬¡ã®ããã«æèšãããŠããŸãã
ã¡ãªã¿ã«ãä»»æã®æ°ã®åŒæ°ã®ç§»æ€å¯èœãªé¢æ°ãäœæãã蚱容å¯èœãªæ¹æ³ã¯ãããŸããã åŒã³åºããã颿°ããåŒã³åºããããšãã«æž¡ãããåŒæ°ã®æ°ã調ã¹ãããã®ç§»æ€å¯èœãªæ¹æ³ã¯ãããŸããã ... printf
ãåŒæ°ã®ä»»æã®æ°ã®æãå
žåçãªCèšèªé¢æ°ã...ã¯ç§»æ€æ§ããªããåã·ã¹ãã ã«å®è£
ããå¿
èŠããããŸãã
ãã®æ¬ã¯
printf
ã«ã€ããŠèª¬æããŠããŸããããŸã
vprintf
ããªããã¿ã€ããšãã¯ã
va_*
ã«ã€ããŠã¯èšåããŠããŸããã ãããã¯Cããã°ã©ãã³ã°èšèªã®ç¬¬2çïŒ1988幎ïŒã«ç»å Žããããã¯æåã®CæšæºïŒC89ãå¥åANSI CïŒã®éçºå§å¡äŒã®ã¡ãªããã§ãã å§å¡äŒã¯ãUNIX OSã®ç§»æ€æ§ãé«ããç®çã§Andrew Koenigãäœæãã
<varargs.h>
åºç€ãšããŠã
<stdarg.h>
ãæšæºã«è¿œå ããŸããã æ¢åã®ã³ã³ãã€ã©ãæ°ããæšæºããµããŒãããããããããã«ã
va_*
ãã¯ãããã¯ããšããŠæ®ã
va_*
ãæ±ºå®ãããŸããã
çŸåšãC89ãš
va_*
ãã¡ããªãŒã®åºçŸã«ãããç§»æ€å¯èœãªå€æ°é¢æ°ãäœæã§ããããã«ãªããŸããã ãããŠããã®ãã¡ããªãŒã®å
éšæ§é ã¯ããŸã ã«èšè¿°ãããŠããããèŠä»¶ããããŸãããããã®çç±ã¯ãã§ã«æããã§ãã
奜å¥å¿ããã
<stdarg.h>
å®è£
ã®äŸãèŠã€ããããšãã§ããŸãã ããšãã°ãåããCæšæºã©ã€ãã©ãªãã¯
Borland Turbo C ++ã®äŸãæäŸã
ãŸã ã
Borland Turbo C ++ã®<stdarg.h> #ifndef _STADARG #define _STADARG #define _AUPBND 1 #define _ADNBND 1 typedef char* va_list #define va_arg(ap, T) \ (*(T*)(((ap) += _Bnd(T, _AUPBND)) - _Bnd(T, _ADNBND))) #define va_end(ap) \ (void)0 #define va_start(ap, A) \ (void)((ap) = (char*)&(A) + _Bnd(A, _AUPBND)) #define _Bnd(X, bnd) \ (sizeof(X) + (bnd) & ~(bnd)) #endif
AMD64çšã®ã¯ããã«æ°ãã
SystemV ABI㯠ã
va_list
ãã®ã¿ã€ãã䜿çšã
va_list
ã
SystemV ABI AMD64ã®va_list typedef struct { unsigned int gp_offset; unsigned int fp_offset; void *overflow_arg_area; void *reg_save_area; } va_list[1];
äžè¬çã«ãåãšãã¯ã
va_*
ã¯ã倿°é¢æ°ã®åŒæ°ããã©ããŒã¹ããããã®æšæºã€ã³ã¿ãŒãã§ã€ã¹ãæäŸããæŽå²çãªçç±ã«ãããããã®å®è£
ã¯ãã³ã³ãã€ã©ãã¿ãŒã²ãããã©ãããã©ãŒã ãããã³ã¢ãŒããã¯ãã£ã«äŸåãããšèšãããšãã§ããŸãã ããã«ãCã§ã¯ãçç¥èšå·ïŒã€ãŸããäžè¬çãªå€æ°é¢æ°ïŒã
va_list
ïŒã€ãŸããããããŒ
<stdarg.h>
ïŒãããåã«ç»å ŽããŸããã ãŸãã
va_list
ã¯çç¥èšå·ã眮ãæããããã«äœæãããã®ã§ã¯ãªããéçºè
ãç§»æ€å¯èœãªå€æ°é¢æ°ãäœæã§ããããã«ããããã«äœæãããŸããã
C ++ã¯äž»ã«Cãšã®åŸæ¹äºææ§ãç¶æããŠãããããäžèšã®ãã¹ãŠãé©çšãããŸãã ããããæ©èœããããŸãã
C ++ã®å€æ°é¢æ°
WG21ã¯ãŒãã³ã°ã°ã«ãŒãã¯ãC ++æšæºã®éçºã«é¢äžããŠããŸãã 1989幎ã«ãæ°ããäœæãããC89æšæºãåºç€ãšãªããC ++èªäœãèšè¿°ããããã«åŸã
ã«å€æŽãããŸããã 1995幎ã«ãææ¡
N0695ã John Miccoãã
åãåãããŸãããèè
ã¯ããã¯ã
va_*
å¶éã倿Žããããšãææ¡ããŸããã
- ãªããªã C ++ã§ã¯ãCãšã¯ç°ãªãã倿°ã®
register
ã¢ãã¬ã¹ãååŸã§ãã倿°é¢æ°ã®æåŸã®ååä»ãåŒæ°ã«ãã®ã¹ãã¬ãŒãžã¯ã©ã¹ãå«ããããšãã§ããŸãã
- ãªããªã C ++ã§åºçŸãããªã³ã¯ã¯ãC倿°é¢æ°ã®æªèšè¿°ã®èŠåã«éåããŸã-ãã©ã¡ãŒã¿ãŒã®ãµã€ãºã¯å®£èšãããåã®ãµã€ãºãšäžèŽããå¿
èŠããããŸã-æåŸã®ååä»ãåŒæ°ã¯ãªã³ã¯ã«ã§ããŸããã ãã以å€ã®å ŽåããããŸããªåäœã
- ãªããªã C ++ã§ã¯ãã ããã©ã«ãã§åŒæ°ã®åãäžãã ããšããæŠå¿µã¯ãããŸããããã®åŸããã¬ãŒãº
ãã©ã¡ãŒã¿ãŒparmN
ã...ã§å®£èšãããŠããå Žåãããã©ã«ãã®åŒæ°ããã¢ãŒã·ã§ã³ã®é©çšåŸã«çããã¿ã€ããšäºææ§ã®ãªãã¿ã€ãã®å Žåãåäœã¯æªå®çŸ©ã§ã
ã«çœ®ãæããå¿
èŠããããŸããã©ã¡ãŒã¿ãŒparmN
ã...ã§å®£èšãããŠããå Žåããã©ã¡ãŒã¿ãŒããªãåŒæ°ãæž¡ããšãã«çããåãšäºææ§ã®ãªãåã®å Žåãåäœã¯æªå®çŸ©ã§ã
ç§ã¯çã¿ãåãã¡åãããã«æåŸã®ãã€ã³ãã翻蚳ããŸããã§ããã ãŸããC ++ Standardã®ã
ããã©ã«ãã®åŒæ°åã®ãšã¹ã«ã¬ãŒã·ã§ã³ ãã¯
[C ++ 17 8.2.2 / 9]ã®ãŸãŸã§ãã ãããŠç¬¬äºã«ãç§ã¯ãã®ãã¬ãŒãºã®æå³ã«ã€ããŠé·ãéå°æãããã¹ãŠãæç¢ºãªã¹ã¿ã³ããŒãCãšæ¯èŒããŸããã N0695ãèªãã åŸã«ããããçè§£ã§ããã®ã¯ãåãããšã§ãã
ãã ãã3ã€ã®å€æŽãã¹ãŠãæ¡çšãããŸãã
[C ++ 98 18.7 / 3] ã C ++ã«æ»ããšãå°ãªããšã1ã€ã®ååä»ããã©ã¡ãŒã¿ãŒïŒãã®å Žåãä»ã®ãã©ã¡ãŒã¿ãŒã«ã¯ã¢ã¯ã»ã¹ã§ããŸããããåŸã§è©³ãã説æããŸãïŒãæã€å€æ°é¢æ°ã®èŠä»¶ã¯ãªããªããååã®ãªãåŒæ°ã®æå¹ãªã¿ã€ãã®ãªã¹ãã¯ãã¯ã©ã¹ã¡ã³ããŒããã³
PODã¿ã€ããžã®ãã€ã³ã¿ãŒã§è£è¶³ãããŸããã
C ++ 03æšæºã§ã¯ã倿°é¢æ°ã«å€æŽã¯ãããŸããã§ããã C ++ 11ã¯ã
std::nullptr_t
åã®ååã®ãªãåŒæ°ã
void*
ã«å€æãå§ããã³ã³ãã€ã©ãŒã®è£éã§ãéèªæãªã³ã³ã¹ãã©ã¯ã¿ãŒãšãã¹ãã©ã¯ã¿ãŒãæã€åããµããŒãã§ããããã«ããŸãã
[C ++ 11 5.2.2 / 7] ã C ++ 14ã§ã¯ãæåŸã®ååä»ããã©ã¡ãŒã¿ãŒãšããŠé¢æ°ãšé
åã䜿çšã§ããããã«ãªã
[C ++ 14 18.10 / 3] ãC ++ 17ã§ã¯ãã©ã ãã«ãã£ãŠãã£ããã£ããã
æ¡åŒµããã¯ãšå€æ°ã®äœ¿çšãçŠæ¢ãããŸãã
[C ++ 17 21.10.1 / 1] ã
ãã®çµæãC ++ã¯èœãšã穎ã«ããŸããŸãªæ©èœã远å ããŸããã éèªæãªã³ã³ã¹ãã©ã¯ã¿/ãã¹ãã©ã¯ã¿ã§æå®ãããŠããªãåãµããŒãã®ã¿ã䟡å€ããããŸãã 以äžã§ã¯ã倿°é¢æ°ã®ãã¹ãŠã®éèªæãªæ©èœã1ã€ã®ãªã¹ãã«ãŸãšããç¹å®ã®äŸã§è£è¶³ããããšããŸãã
倿°é¢æ°ãç°¡åãã€èª€ã£ãŠäœ¿çšããæ¹æ³
- ææ Œãããåã§æåŸã®ååä»ãåŒæ°ã宣èšããã®ã¯ééã£ãŠããŸãã
char
ã signed char
ã unsigned char
ã singed short
ã unsigned short
ãŸãã¯float
æšæºã«åŸã£ãçµæã¯ãæªå®çŸ©ã®åäœã«ãªããŸãã
ç¡å¹ãªã³ãŒã void foo(float n, ...) { va_list va; va_start(va, n); std::cout << va_arg(va, int) << std::endl; va_end(va); }
æå
ã«ãããã¹ãŠã®ã³ã³ãã€ã©ïŒgccãclangãMSVCïŒã®ãã¡ã clangã®ã¿ãèŠåãçºè¡ããŸããã
ã¯ã©ã³èŠå ./test.cpp:7:18: warning: passing an object that undergoes default argument promotion to 'va_start' has undefined behavior [-Wvarargs] va_start(va, n); ^
ãããŠããã¹ãŠã®å Žåã«ãããŠãã³ã³ãã€ã«ãããã³ãŒãã¯æ£ããåäœããŸãããããããåœãŠã«ããã¹ãã§ã¯ãããŸããã
æ£ããã§ããã void foo(double n, ...) { va_list va; va_start(va, n); std::cout << va_arg(va, int) << std::endl; va_end(va); }
- æåŸã®ååä»ãåŒæ°ãåç
§ãšããŠå®£èšããã®ã¯æ£ãããããŸããã ä»»æã®ãªã³ã¯ã ãã®å Žåã®æšæºã¯ãæªå®çŸ©ã®åäœãä¿èšŒããŸãã
ç¡å¹ãªã³ãŒã void foo(int& n, ...) { va_list va; va_start(va, n); std::cout << va_arg(va, int) << std::endl; va_end(va); }
gcc 7.3.0ã¯ãåäžã®ã³ã¡ã³ããªãã§ãã®ã³ãŒããã³ã³ãã€ã«ããŸããã lang6.0.0ã¯èŠåãçºè¡ããŸããããããã§ãã³ã³ãã€ã«ããŸããã
ã¯ã©ã³èŠå ./test.cpp:7:18: warning: passing an object of reference type to 'va_start' has undefined behavior [-Wvarargs] va_start(va, n); ^
ã©ã¡ãã®å Žåããããã°ã©ã ã¯æ£ããæ©èœããŸããïŒå¹žéãªããšã«ãããªãã¯ããã«é Œãããšã¯ã§ããŸããïŒã ãããã MSVC 19.15.26730ã¯ããèªäœãéç«ãããŠããŸã-ã³ãŒãã®ã³ã³ãã€ã«ãæåŠããŸããã va_start
åŒæ°va_start
åç
§ã§ãã£ãŠã¯ãªãva_start
ãã
MSVCããã®ãšã©ãŒ c:\program files (x86)\microsoft visual studio\2017\community\vc\tools\msvc\14.15.26726\include\vadefs.h(151): error C2338: va_start argument must not have reference type and must not be parenthesized
ããŠãæ£ãããªãã·ã§ã³ã¯ãããšãã°æ¬¡ã®ããã«ãªããŸã void foo(int* n, ...) { va_list va; va_start(va, n); std::cout << va_arg(va, int) << std::endl; va_end(va); }
va_arg
type- char
ã short
ãŸãã¯float
va_arg
äžããããã«èŠæ±ããã®ã¯ééã£ãŠããŸãã
ç¡å¹ãªã³ãŒã #include <cstdarg> #include <iostream> void foo(int n, ...) { va_list va; va_start(va, n); std::cout << va_arg(va, int) << std::endl; std::cout << va_arg(va, float) << std::endl; std::cout << va_arg(va, int) << std::endl; va_end(va); } int main() { foo(0, 1, 2.0f, 3); return 0; }
ããã§ãã£ãšé¢çœãã§ãã ã³ã³ãã€ã«æã®gccã¯ã float
ã§ã¯ãªãdouble
ã䜿çšããå¿
èŠããããšããèŠåãåºããŸãããã®ã³ãŒãããŸã å®è¡ãããŠããå Žåãããã°ã©ã ã¯ãšã©ãŒã§çµäºããŸãã
GCCèŠå ./test.cpp:9:15: warning: 'float' is promoted to 'double' when passed through '...' std::cout << va_arg(va, float) << std::endl; ^~~~~~ ./test.cpp:9:15: note: (so you should pass 'double' not 'float' to 'va_arg') ./test.cpp:9:15: note: if this code is reached, the program will abort
確ãã«ãããã°ã©ã ã¯ç¡å¹ãªåœä»€ã«é¢ããèŠæ
ã§ã¯ã©ãã·ã¥ããŸãã
ãã³ãåæã¯ãããã°ã©ã ãSIGILLã·ã°ãã«ãåä¿¡ããããšã瀺ããŠããŸãã ãŸãã va_list
ã®æ§é ã瀺ããŠããŸãã 32ãããã®å Žåãããã¯
va = 0xfffc6918 ""
ã€ãŸã va_list
ã¯åãªãchar*
ã§ãã 64ãããã®å ŽåïŒ
va = {{gp_offset = 16, fp_offset = 48, overflow_arg_area = 0x7ffef147e7e0, reg_save_area = 0x7ffef147e720}}
ã€ãŸã SystemV ABI AMD64ã§èª¬æãããŠãããšããã§ãã
ã³ã³ãã€ã«æã®clangã¯ãæªå®çŸ©ã®åäœãèŠåãã float
ãdouble
眮ãæããããšãææ¡ããŸãã
ã¯ã©ã³èŠå ./test.cpp:9:26: warning: second argument to 'va_arg' is of promotable type 'float'; this va_arg has undefined behavior because arguments will be promoted to 'double' [-Wvarargs] std::cout << va_arg(va, float) << std::endl; ^~~~~
ããããããã°ã©ã ãã¯ã©ãã·ã¥ããããšã¯ãªããªãã32ãããããŒãžã§ã³ã§ã¯ä»¥äžãçæãããŸãã
1 0 1073741824
64ãããïŒ
1 0 3
MSVCã¯ã /Wall
ãã£ãŠããèŠåãªãã§ã®ã¿ãŸã£ããåãçµæãçæããŸãã
ããã§ã32ããããš64ãããã®éãã¯ãæåã®ã±ãŒã¹ã§ã¯ABIããã¹ãŠã®åŒæ°ãã¹ã¿ãã¯çµç±ã§åŒã³åºããã颿°ã«æž¡ãã2çªç®ã§ã¯æåã®4ã€ïŒWindowsïŒãŸãã¯6ã€ïŒLinuxïŒã®åŒæ°ãããã»ããµã¬ãžã¹ã¿ãééããæ®ããã¹ã¿ãã¯[ wiki ]ã ãã ãã4ã€ã®åŒæ°ã§ã¯ãªã19ã§foo
ãåŒã³åºããŠåãæ¹æ³ã§åºåãããšãçµæã¯åãã«ãªããŸãã32ãããããŒãžã§ã³ã§ã¯å®å
šã«æ··ä¹±ãã64ãããããŒãžã§ã³ã§ã¯ãã¹ãŠã®float
ããŒãã«ãªããŸãã ã€ãŸã ãã€ã³ãã¯ãã¡ããABIã§ãããåŒæ°ãæž¡ãããã«ã¬ãžã¹ã¿ã䜿çšããããšã§ã¯ãããŸããã
ãŸãããã¡ãããããããããã« void foo(int n, ...) { va_list va; va_start(va, n); std::cout << va_arg(va, int) << std::endl; std::cout << va_arg(va, double) << std::endl; std::cout << va_arg(va, int) << std::endl; va_end(va); }
- ååã®ãªãåŒæ°ãšããŠéèŠãªã³ã³ã¹ãã©ã¯ã¿ãŸãã¯ãã¹ãã©ã¯ã¿ãæã€ã¯ã©ã¹ã®ã€ã³ã¹ã¿ã³ã¹ãæž¡ãããšã¯æ£ãããããŸããã ãã¡ããããã®ã³ãŒãã®éåœããä»ããã§ã³ã³ãã€ã«ããŠå®è¡ããã以äžã«ããªããè奮ãããªãéãã¯ã
ç¡å¹ãªã³ãŒã #include <cstdarg> #include <iostream> struct Bar { Bar() { std::cout << "Bar default ctor" << std::endl; } Bar(const Bar&) { std::cout << "Bar copy ctor" << std::endl; } ~Bar() { std::cout << "Bar dtor" << std::endl; } }; struct Cafe { Cafe() { std::cout << "Cafe default ctor" << std::endl; } Cafe(const Cafe&) { std::cout << "Cafe copy ctor" << std::endl; } ~Cafe() { std::cout << "Cafe dtor" << std::endl; } }; void foo(int n, ...) { va_list va; va_start(va, n); std::cout << "Before va_arg" << std::endl; const auto b = va_arg(va, Bar); va_end(va); } int main() { Bar b; Cafe c; foo(1, b, c); return 0; }
åã³Clangããã峿 Œã«ãªããŸããã 圌va_arg
ã va_arg
ã®2çªç®ã®åŒæ°ãPODã¿ã€ãã§va_arg
ãªãããããã®ã³ãŒãã®ã³ã³ãã€ã«ãæåŠããããã°ã©ã ãèµ·åæã«va_arg
ããããšãèŠåããŸãã
ã¯ã©ã³èŠå ./test.cpp:23:31: error: second argument to 'va_arg' is of non-POD type 'Bar' [-Wnon-pod-varargs] const auto b = va_arg(va, Bar); ^~~ ./test.cpp:31:12: error: cannot pass object of non-trivial type 'Bar' through variadic function; call will abort at runtime [-Wnon-pod-varargs] foo(1, b, c); ^
ãŸã -Wno-non-pod-varargs
ãã©ã°ã䜿çšããŠã³ã³ãã€ã«ãããšããããªããŸãã
MSVCã¯ããã®å Žåã«éèŠãªã³ã³ã¹ãã©ã¯ã¿ãŒã䜿çšããããšã¯ç§»æ€æ§ããªããšèŠåããŸãã
MSVCããã®èŠå d:\my documents\visual studio 2017\projects\test\test\main.cpp(31): warning C4840: "Bar"
ãã ããã³ãŒãã¯æ£ããã³ã³ãã€ã«ããã³å®è¡ãããŸãã ã³ã³ãœãŒã«ã§ä»¥äžãååŸãããŸãã
æã¡äžãçµæ Bar default ctor Cafe default ctor Before va_arg Bar copy ctor Bar dtor Cafe dtor Bar dtor
ã€ãŸã ã³ããŒã¯va_arg
ãåŒã³åºãããšãã«ã®ã¿äœæãããåŒæ°ã¯åç
§ã«ãã£ãŠæž¡ãããŸãã ã©ããããããèªæã§ã¯ãããŸããããæšæºã§ã¯èš±å¯ãããŠããŸãã
gcc 6.3.0㯠ãåäžã®ã³ã¡ã³ããªãã§ã³ã³ãã€ã«ããŸãã åºåã¯åãã§ãïŒ
æã¡äžãçµæ Bar default ctor Cafe default ctor Before va_arg Bar copy ctor Bar dtor Cafe dtor Bar dtor
gcc 7.3.0ãäœã«ã€ããŠãèŠåããŸããããåäœã¯å€åããŠããŸãïŒ
æã¡äžãçµæ Bar default ctor Cafe default ctor Cafe copy ctor Bar copy ctor Before va_arg Bar copy ctor Bar dtor Bar dtor Cafe dtor Cafe dtor Bar dtor
ã€ãŸã ãã®ããŒãžã§ã³ã®ã³ã³ãã€ã©ã¯åŒæ°ãå€ã§æž¡ããåŒã³åºããããšã va_arg
ã¯å¥ã®ã³ããŒãäœæããŸãã ã³ã³ã¹ãã©ã¯ã¿/ãã¹ãã©ã¯ã¿ã«å¯äœçšãããå Žåãgccã®6çªç®ãã7çªç®ã®ããŒãžã§ã³ã«åãæ¿ãããšãã«ãã®éããæ¢ãã®ã¯æ¥œããã§ãããã
ãšããã§ãã¯ã©ã¹ãžã®åç
§ãæç€ºçã«æž¡ããèŠæ±ããå ŽåïŒ
å¥ã®ééã£ãã³ãŒã void foo(int n, ...) { va_list va; va_start(va, n); std::cout << "Before va_arg" << std::endl; const auto& b = va_arg(va, Bar&); va_end(va); } int main() { Bar b; Cafe c; foo(1, std::ref(b), c); return 0; }
ãã¹ãŠã®ã³ã³ãã€ã©ããšã©ãŒãã¹ããŒããŸãã æšæºã§èŠæ±ãããŠãããšããã
äžè¬çã«ãæ¬åœã«ãããå Žåã¯ãåŒæ°ããã€ã³ã¿ã§æž¡ãã»ããè¯ãã§ãããã
ãã®ããã« void foo(int n, ...) { va_list va; va_start(va, n); std::cout << "Before va_arg" << std::endl; const auto* b = va_arg(va, Bar*); va_end(va); } int main() { Bar b; Cafe c; foo(1, &b, &c); return 0; }
ãªãŒããŒããŒã解決ãšå€æ°é¢æ°
äžæ¹ã§ã¯ããã¹ãŠãåçŽã§ããæšæºãŸãã¯ãŠãŒã¶ãŒå®çŸ©ã®å倿ã®å Žåã§ããçç¥èšå·ãšã®äžèŽã¯ãéåžžã®ååä»ãåŒæ°ãšã®äžèŽãããå£ããŸãã
éè² è·ã®äŸ #include <iostream> void foo(...) { std::cout << "C variadic function" << std::endl; } void foo(int) { std::cout << "Ordinary function" << std::endl; } int main() { foo(1); foo(1ul); foo(); return 0; }
æã¡äžãçµæ $ ./test Ordinary function Ordinary function C variadic function
ãã ããããã¯ãåŒæ°ãªãã®
foo
ã®åŒã³åºããåå¥ã«èæ
®ããªãéãæ©èœããŸãã
åŒæ°ãªãã§fooãåŒã³åºã #include <iostream> void foo(...) { std::cout << "C variadic function" << std::endl; } void foo() { std::cout << "Ordinary function without arguments" << std::endl; } int main() { foo(1); foo(); return 0; }
ã³ã³ãã€ã©ãŒåºå ./test.cpp:16:9: error: call of overloaded 'foo()' is ambiguous foo(); ^ ./test.cpp:3:6: note: candidate: void foo(...) void foo(...) ^~~ ./test.cpp:8:6: note: candidate: void foo() void foo() ^~~
ãã¹ãŠã¯æšæºã«æºæ ããŠããŸããåŒæ°ã¯ãããŸãã-çç¥èšå·ãšã®æ¯èŒã¯ãããŸããããŸãããªãŒããŒããŒãã解決ããããšãå€å颿°ã¯éåžžã®ãã®ããæªããªããŸããã
ããã«ããããããã倿°é¢æ°ã䜿çšãã䟡å€ãããã®ã¯ãã€ã§ãã
ããŠãå€é颿°ã¯æã
éåžžã«æç¢ºã«æ¯ãèãããC ++ã®ã³ã³ããã¹ãã§ã¯ç§»æ€æ§ãäœãããšã容æã«å€æããŸãã ã倿°C颿°ãäœæãŸãã¯äœ¿çšããªãã§ãã ããããªã©ãã€ã³ã¿ãŒãããã«ã¯å€ãã®ãã³ãããããŸãããC ++æšæºããã®ãµããŒãã¯åé€ãããŸããã ãããã®æ©èœã«ã¯ããã€ãã®å©ç¹ããããŸããïŒ ããããã«ã
- æãäžè¬çã§æçœãªã±ãŒã¹ã¯ãäžäœäºææ§ã§ãã ããã§ã¯ããµãŒãããŒãã£ã®Cã©ã€ãã©ãªã®äœ¿çšïŒJNIã®å ŽåïŒãšC ++å®è£
ãžã®C APIã®æäŸã®äž¡æ¹ãå«ããŸãã
- SFINAE C ++ã§ã¯ã倿°é¢æ°ã«ååä»ãåŒæ°ãå¿
èŠãªãããšãããã³ãªãŒããŒããŒãããã颿°ã解決ãããšãã«å€æ°é¢æ°ãæåŸãšèŠãªãããããšïŒå°ãªããšã1ã€ã®åŒæ°ãããå ŽåïŒãéåžžã«äŸ¿å©ã§ãã ãŸããä»ã®é¢æ°ãšåæ§ã«ã倿°é¢æ°ã¯å®£èšããããšããã§ããŸããããåŒã³åºãããšã¯ã§ããŸããã
äŸ template <class T> struct HasFoo { private: template <class U, class = decltype(std::declval<U>().foo())> static void detect(const U&); static int detect(...); public: static constexpr bool value = std::is_same<void, decltype(detect(std::declval<T>()))>::value; };
C ++ 14ã§ã¯ãå°ãç°ãªãæ¹æ³ã§å®è¡ã§ããŸãã
å¥ã®äŸ template <class T> struct HasFoo { private: template <class U, class = decltype(std::declval<U>().foo())> static constexpr bool detect(const U*) { return true; } template <class U> static constexpr bool detect(...) { return false; } public: static constexpr bool value = detect<T>(nullptr); };
ãããŠããã®å Žåãæ¢ã«detect(...)
ããåŒæ°detect(...)
ãåŒã³åºãããšãã§ãããã®ãç£èŠããå¿
èŠããããŸãã ããã€ãã®è¡ã倿Žãã倿°é¢æ°ã®ãã¹ãŠã®çæãæ¬ ããææ°ã®ä»£æ¿é¢æ°ã䜿çšããããšæããŸãã
ããªã¢ã³ããã³ãã¬ãŒããŸãã¯çŸä»£ã®C ++ã§ä»»æã®æ°ã®åŒæ°ãã颿°ãäœæããæ¹æ³
å¯å€ãã³ãã¬ãŒãã®ã¢ã€ãã¢ã¯ã2004幎ã«Douglas GregorãJakkoJÀrviãGary Powellã«ãã£ãŠææ¡ãããŸããã ãããã®å€æ°ãã³ãã¬ãŒããå
¬åŒã«ãµããŒããããC ++ 11æšæºãæ¡çšããã7幎åã ãã®èŠæ Œã«ã¯ãææ¡ã®ç¬¬3çã§ãã
N2080ãå«ãŸããŠããŸãã
ããã°ã©ããŒãä»»æã®æ°ã®åŒæ°ããã¿ã€ãã»ãŒãïŒããã³ããŒã¿ãã«ïŒïŒé¢æ°ãäœæã§ããããã«ãæåãã倿°ãã³ãã¬ãŒããäœæãããŸãããå¥ã®ç®æšã¯ãå¯å€æ°ã®ãã©ã¡ãŒã¿ãŒãæã€ã¯ã©ã¹ãã³ãã¬ãŒãã®ãµããŒããç°¡çŽ åããããšã§ãããçŸåšã¯å¯å€æ©èœã«ã€ããŠã®ã¿èª¬æããŠããŸãã倿°ãã³ãã¬ãŒãã¯ãC ++ [C ++ 17 17.5.3]ã« 3ã€ã®æ°ããæŠå¿µããããããŸããã- ãã³ãã¬ãŒããã©ã¡ãŒã¿ããã±ãŒãžïŒãã³ãã¬ãŒããã©ã¡ãŒã¿ããã¯ã¯ïŒ -ä»»æã®ãã³ãã¬ãŒãåŒæ°ã®æ°ïŒ0ãå«ãïŒã転éããããšãå¯èœã§ãã代ããã«ãã®ãã¡ããã©ã¡ãŒã¿ã»ãã³ãã¬ãŒãã§ãã
- 颿°ãã©ã¡ãŒã¿ãŒã®ããã±ãŒãžïŒfunction parameter packïŒ-ãããã£ãŠãããã¯ïŒ0ãå«ãïŒä»»æã®æ°ã®é¢æ°åŒæ°ãåã颿°ãã©ã¡ãŒã¿ãŒã§ãã
- ãŸããããã±ãŒãžã®å±éïŒpack expansionïŒã®ã¿ãããã©ã¡ãŒã¿ãŒããã±ãŒãžã§å®è¡ã§ããŸãã
äŸ template <class ... Args> void foo(const std::string& format, Args ... args) { printf(format.c_str(), args...); }
class ... Args
â ,
Args ... args
â ,
args...
â .
ãã©ã¡ãŒã¿ããã±ãŒãžãå±éã§ããå Žæã𿹿³ã®å®å
šãªãªã¹ãã¯ãæšæºèªäœ[C ++ 17 17.5.3 / 4]ã«èšèŒãããŠããŸãããããŠã倿°é¢æ°ã®è°è«ã®æèã§ã¯ããããèšãã ãã§ååã§ãïŒé¢æ°ãã©ã¡ãŒã¿ãŒããã±ãŒãžã¯ãå¥ã®é¢æ°ã®åŒæ°ãªã¹ãã«å±éã§ããŸã template <class ... Args> void bar(const std::string& format, Args ... args) { foo<Args...>(format.c_str(), args...); }
ãŸãã¯åæåãªã¹ãã« template <class ... Args> void foo(const std::string& format, Args ... args) { const auto list = {args...}; }
ãŸãã¯ã©ã ããã£ããã£ãªã¹ãã« template <class ... Args> void foo(const std::string& format, Args ... args) { auto lambda = [&format, args...] () { printf(format.c_str(), args...); }; lambda(); }
颿°ãã©ã¡ãŒã¿ã®å¥ã®ããã±ãŒãžã¯ãç³ã¿èŸŒã¿åŒã§å±éã§ããŸã template <class ... Args> int foo(Args ... args) { return (0 + ... + args); }
ç³ã¿èŸŒã¿ã¯C ++ 14ã§ç»å Žããåé
ããã³ãã€ããªãå³ããã³å·Šã«ãªããŸããæãå®å
šãªèª¬æã¯ããã€ãã®ããã«ãæšæº[C ++ 17 8.1.6]ã«ãããŸãã
äž¡æ¹ã®ã¿ã€ãã®ãã©ã¡ãŒã¿ãŒããã±ãŒãžã¯ãsizeof ...æŒç®åã«å±éã§ããŸãã template <class ... Args> void foo(Args ... args) { const auto size1 = sizeof...(Args); const auto size2 = sizeof...(args); }
æç€ºçãªçç¥èšå·ããã±ãŒãžãé瀺ããéã«ãããŸããŸãªãã³ãã¬ãŒãïŒãµããŒãããããã«å¿
èŠãšããããã¿ãŒã³ïŒé瀺ããããã®ææ§ããé¿ããããã«ãäŸãã° template <class ... Args> void foo() { using OneTuple = std::tuple<std::tuple<Args>...>; using NestTuple = std::tuple<std::tuple<Args...>>; }
OneTuple
â (
std:tuple<std::tuple<int>>, std::tuple<double>>
),
NestTuple
â , â (
std::tuple<std::tuple<int, double>>
).
倿°ãã³ãã¬ãŒãã䜿çšããprintfã®å®è£
äŸ
ãã§ã«è¿°ã¹ãããã«ã倿°ãã³ãã¬ãŒãã¯Cã®å€æ°é¢æ°ã®çŽæ¥ã®ä»£æ¿ãšããŠãäœæãããŸããããããã®ãã³ãã¬ãŒãã®äœæè
èªèº«ã¯ãéåžžã«ã·ã³ãã«ã§ãããªããã¿ã€ãã»ãŒããªããŒãžã§ã³ãææ¡ãprintf
ãŸããããã³ãã¬ãŒãã®printf void printf(const char* s) { while (*s) { if (*s == '%' && *++s != '%') throw std::runtime_error("invalid format string: missing arguments"); std::cout << *s++; } } template <typename T, typename ... Args> void printf(const char* s, T value, Args ... args) { while (*s) { if (*s == '%' && *++s != '%') { std::cout << value; return printf(++s, args...); } std::cout << *s++; } throw std::runtime_error("extra arguments provided to printf"); }
çãããã®ã¯ã倿°åŒæ°ã®åæã®ãã®ãã¿ãŒã³ãçŸãã-ãªãŒããŒããŒãããã颿°ã®ååž°åŒã³åºããéããŠãããããç§ã¯ãŸã ååž°ã®ãªããªãã·ã§ã³ã奜ã¿ãŸãããã³ãã¬ãŒãäžã®printfãšååž°ãªã template <typename ... Args> void printf(const std::string& fmt, const Args& ... args) { size_t fmtIndex = 0; size_t placeHolders = 0; auto printFmt = [&fmt, &fmtIndex, &placeHolders]() { for (; fmtIndex < fmt.size(); ++fmtIndex) { if (fmt[fmtIndex] != '%') std::cout << fmt[fmtIndex]; else if (++fmtIndex < fmt.size()) { if (fmt[fmtIndex] == '%') std::cout << '%'; else { ++fmtIndex; ++placeHolders; break; } } } }; ((printFmt(), std::cout << args), ..., (printFmt())); if (placeHolders < sizeof...(args)) throw std::runtime_error("extra arguments provided to printf"); if (placeHolders > sizeof...(args)) throw std::runtime_error("invalid format string: missing arguments"); }
ãªãŒããŒããŒã解決ããã³å€æ°ãã³ãã¬ãŒã颿°
解決ãããšãããããã®å€å颿°ã¯ãä»ã®åŸã«ããã³ãã¬ãŒããšããŠãæãå°éæ§ã®äœããã®ãšèŠãªãããŸãããã ããåŒæ°ãªãã®åŒã³åºãã®å Žåã¯åé¡ãããŸãããéè² è·ã®äŸ #include <iostream> void foo(int) { std::cout << "Ordinary function" << std::endl; } void foo() { std::cout << "Ordinary function without arguments" << std::endl; } template <class T> void foo(T) { std::cout << "Template function" << std::endl; } template <class ... Args> void foo(Args ...) { std::cout << "Template variadic function" << std::endl; } int main() { foo(1); foo(); foo(2.0); foo(1, 2); return 0; }
æã¡äžãçµæ $ ./test Ordinary function Ordinary function without arguments Template function Template variadic function
éè² è·ã解決ããããšã倿°ãã³ãã¬ãŒã颿°ã¯å€æ°C颿°ã®ã¿ããã€ãã¹ã§ããŸãïŒãªãããããæ··åšãããã®ã§ããïŒïŒãäŸå€-ãã¡ããïŒ-åŒæ°ãªãã§åŒã³åºããŸããåŒæ°ãªãã§åŒã³åºã #include <iostream> void foo(...) { std::cout << "C variadic function" << std::endl; } template <class ... Args> void foo(Args ...) { std::cout << "Template variadic function" << std::endl; } int main() { foo(1); foo(); return 0; }
æã¡äžãçµæ $ ./test Template variadic function C variadic function
çç¥èšå·ãšã®æ¯èŒããããŸã-察å¿ãã颿°ã¯å€±ãããçç¥èšå·ãšã®æ¯èŒã¯ãããŸãã-ãã³ãã¬ãŒã颿°ã¯éãã³ãã¬ãŒã颿°ãããå£ã£ãŠããŸããå¯å€ãã³ãã¬ãŒã颿°ã®é床ã«é¢ããç°¡åãªã¡ã¢
2008幎ããã€ãã¯ãžã§ãªãŒã¯ææ¡N2772ãC ++æšæºåå§å¡äŒã«æåºããŸãããããã§ã倿°ãã³ãã¬ãŒã颿°ã¯ãåŒæ°ãåæåãªã¹ãïŒstd::initializer_list
ïŒã§ããåæ§ã®é¢æ°ãããåäœãé
ãããšãå®éã«ç€ºããŸãããããã¯äœè
èªèº«ã®çè«çå®èšŒã«åãããã®ã®ãšããžã§ãªãŒã¯ãå®è£
ããããšãææ¡ãstd::min
ãstd::max
ãããŠstd::minmax
ããã¯ãåæåãªã¹ãã®ä»£ããã®å€åœ¢ãã¿ãŒã³ãä»ããŠè¡ãããŸãããããããã§ã«2009幎ã«åè«ããããŸããããžã§ãªã®ãã¹ãã§ããé倧ãªééãããçºèŠãããŸããïŒèªåèªèº«ã«ããæããŸãïŒãæ°ãããã¹ãïŒãã¡ããšãã¡ããã芧ãã ããïŒã¯ã倿°ãã³ãã¬ãŒã颿°ãããã«é«éã§ãå Žåã«ãã£ãŠã¯ããªãé«éã§ããããšã瀺ããŸãããé©ãããšã§ã¯ãããŸãã åæåãªã¹ãã¯ãã®èŠçŽ ã®ã³ããŒãäœæããŸãã倿°ãã³ãã¬ãŒãã®å Žåãã³ã³ãã€ã«æ®µéã§å€ããã«ãŠã³ãã§ããŸããããã«ãããããããC ++ 11以éã®æšæºstd::min
ã§ã¯std::max
ãstd::minmax
ã¯éåžžã®ãã³ãã¬ãŒã颿°ã§ãããåæåãªã¹ããä»ããŠæž¡ãããä»»æã®æ°ã®åŒæ°ã§ããç°¡åãªèŠçŽãšçµè«
ãããã£ãŠãCã¹ã¿ã€ã«ã®å€æ°é¢æ°ïŒ- 圌ãã¯ãåŒæ°ã®æ°ãã¿ã€ããç¥ããŸãããéçºè
ã¯ãæ®ãã®æ
å ±ãæž¡ãããã«ã颿°ã®åŒæ°ã®äžéšã䜿çšããå¿
èŠããããŸãã
- ååã®ãªãåŒæ°ïŒããã³æåŸã®ååã®åŒæ°ïŒã®åãæé»çã«äžããŸãããããå¿ãããšããããŸããªæ¯ãèããããŸãã
- ãããã¯çŽç²ãªCãšã®åŸæ¹äºææ§ãç¶æããŠãããããåç
§ã«ããåŒæ°ã®åãæž¡ãããµããŒãããŠããŸããã
- C ++ 11ããåã¯ãPODåã§ã¯ãªãåŒæ°ã¯ãµããŒããããŠããŸããã§ãããC++ 11以éã®éèªæãªåã®ãµããŒãã¯ãã³ã³ãã€ã©ã®è£éã«ä»»ãããŠããŸãããã€ãŸã ã³ãŒãã®åäœã¯ãã³ã³ãã€ã©ãšãã®ããŒãžã§ã³ã«äŸåããŸãã
倿°é¢æ°ã®å¯äžã®äœ¿çšã¯ãC ++ã³ãŒãã§C APIãšå¯Ÿè©±ããããšã§ããSFINAEãå«ãä»ã®ãã¹ãŠã«ã€ããŠã以äžã®å€æ°ãã³ãã¬ãŒã颿°ããããŸãã- ãã¹ãŠã®åŒæ°ã®æ°ãšã¿ã€ããç¥ã£ãŠããŸãã
- åã»ãŒãã§ãåŒæ°ã®åã倿Žããªãã§ãã ããã
- å€ããã€ã³ã¿ãåç
§ããŠãããŒãµã«ãªã³ã¯ãªã©ããããã圢åŒã§åŒæ°ãæž¡ãããšãã§ããŸãã
- ä»ã®C ++颿°ãšåæ§ã«ãåŒæ°ã®ã¿ã€ãã«å¶éã¯ãããŸããã
- ( C ), .
倿°ãã³ãã¬ãŒã颿°ã¯ãCã¹ã¿ã€ã«ã®å¯Ÿå¿ãã颿°ãšæ¯èŒããŠããåé·ã§ããå Žåããããæã«ã¯ç¬èªã®ãªãŒããŒããŒããããéãã³ãã¬ãŒãããŒãžã§ã³ïŒååž°çãªåŒæ°ãã©ããŒãµã«ïŒãå¿
èŠãšããããšãããããŸããèªã¿åããšæžã蟌ã¿ãå°é£ã§ããããããããã¯ãã¹ãŠããªã¹ããããŠããæ¬ ç¹ããªãããªã¹ããããŠããå©ç¹ãååšããããšã§ãå¯ŸäŸ¡ãæ¯æãããŸããçµè«ã¯ç°¡åã§ããCã¹ã¿ã€ã«ã®ããªãšãŒã·ã§ã³é¢æ°ã¯ãäžäœäºææ§ã®ããã ãã«C ++ã®ãŸãŸã§ãããèãæã€ããã®å¹
åºããªãã·ã§ã³ãæäŸããŸããçŸä»£ã®C ++ã§ã¯ãæ°ãããã®ãèšè¿°ããªãããšãã§ããã°æ¢åã®å€æ°C颿°ã䜿çšããªãããšã匷ããå§ãããŸããå¯å€ãã³ãã¬ãŒã颿°ã¯ãææ°ã®C ++ã®äžçã«å±ããã¯ããã«å®å
šã§ãããããã䜿çšããŸããæç®ãšæ
å ±æº
PS
äžèšã®æžç±ã®é»åçããããäžã§ç°¡åã«èŠã€ããŠããŠã³ããŒãã§ããŸãããããããããåæ³ãã©ããã¯ããããŸããã®ã§ããªã³ã¯ã¯æäŸããŸããã