|
| 1 | +--- |
| 2 | +title: Variadic arguments |
| 3 | +cppdoc: |
| 4 | + keys: ["cpp.lang.variadic_arguments"] |
| 5 | +--- |
| 6 | + |
| 7 | +import { Decl, DeclDoc } from "@components/decl-doc"; |
| 8 | +import { DR, DRList } from "@components/defect-report"; |
| 9 | +import { Desc, DescList, DocLink } from '@components/index'; |
| 10 | +import { autoRev, Revision, RevisionBlock } from "@components/revision"; |
| 11 | +import Behavior from "@components/Behavior.astro"; |
| 12 | +import Missing from "@components/Missing.astro"; |
| 13 | + |
| 14 | +Allows a function to accept any number of extra arguments. |
| 15 | + |
| 16 | +A function is a variadic if the last parameter of its <DocLink src="/cpp/language/function">parameter list</DocLink> is an ellipsis (`...`). |
| 17 | + |
| 18 | +<RevisionBlock traits={[{ trait: "deprecated", since: "C++26" }]}> |
| 19 | + The comma preceding the ellipsis can be omitted. |
| 20 | +</RevisionBlock> |
| 21 | + |
| 22 | +```cpp |
| 23 | +// the function declared as follows |
| 24 | +int printx(const char* fmt, ...); |
| 25 | +int printx(const char* fmt...); // same as above, but deprecated since C++26 |
| 26 | + |
| 27 | +// may be called with one or more arguments: |
| 28 | +printx("hello world"); |
| 29 | +printx("a=%d b=%d", a, b); |
| 30 | + |
| 31 | +int printy(..., const char* fmt); // error: ... can only be the last parameter |
| 32 | +int printz(...); // valid, but the arguments cannot be accessed portably |
| 33 | +``` |
| 34 | +
|
| 35 | +<RevisionBlock since="C++11"> |
| 36 | + This is different from a function <DocLink src="/cpp/language/parameter_pack">parameter pack</DocLink> expansion, which is indicated by an ellipsis that is a part of a parameter declarator, rather than an ellipsis being a parameter alone. Both parameter pack expansion and the “variadic” ellipsis may appear in the declaration of a function template, as in the case of <Missing>`std::is_function`</Missing>. |
| 37 | +</RevisionBlock> |
| 38 | +
|
| 39 | +## Default argument promotions |
| 40 | +
|
| 41 | +When a variadic function is called, after lvalue-to-rvalue, array-to-pointer, and function-to-pointer <DocLink src="/cpp/language/implicit_cast">conversions</DocLink>, each argument that is a part of the variable argument list undergoes additional conversions known as _default argument promotions_: |
| 42 | +
|
| 43 | +<RevisionBlock since="C++11"> |
| 44 | + - <Missing>`std::nullptr_t`</Missing> is converted to `void*`. |
| 45 | +</RevisionBlock> |
| 46 | +
|
| 47 | +- `float` arguments are converted to `double` as in <DocLink src="/cpp/language/implicit_cast">floating-point promotion</DocLink>. |
| 48 | +- `bool`, `char`, `short`, and unscoped enumerations are converted to `int` or wider integer types as in <DocLink src="/cpp/language/implicit_cast">integral promotion</DocLink>. |
| 49 | +
|
| 50 | +<Revision until="C++11">Non-POD class types</Revision><Revision since="C++11">Scoped enumerations and class types with an eligible non-trivial copy constructor, an eligible non-trivial move constructor, or a non-trivial destructor</Revision> are conditionally-supported in potentially-evaluated calls with <Behavior kind="impl-def">implementation-defined</Behavior> semantics (these types are always supported in <DocLink src="/cpp/language/expressions">unevaluated calls</DocLink>). |
| 51 | +
|
| 52 | +Because variadic parameters have the lowest rank for the purpose of <DocLink src="/cpp/language/overload_resolution">overload resolution</DocLink>, they are commonly used as the catch-all fallbacks in <DocLink src="/cpp/language/sfinae">SFINAE</DocLink>. |
| 53 | +
|
| 54 | +Within the body of a function that uses variadic arguments, the values of these arguments may be accessed using the <Missing>\<cstdarg\> library facilities</Missing>: |
| 55 | +
|
| 56 | +<DescList> |
| 57 | + <Desc kind="function macro"> |
| 58 | + <Fragment slot="item"> |
| 59 | + <Missing>va_start</Missing> |
| 60 | + </Fragment> |
| 61 | + enables access to variadic function arguments |
| 62 | + </Desc> |
| 63 | + <Desc kind="function macro"> |
| 64 | + <Fragment slot="item"> |
| 65 | + <Missing>va_arg</Missing> |
| 66 | + </Fragment> |
| 67 | + accesses the next variadic function argument |
| 68 | + </Desc> |
| 69 | + <Desc kind="function macro" autorevSince="C++11"> |
| 70 | + <RevisionBlock slot="item" since="C++11" vertical noborder> |
| 71 | + <Missing>va_copy</Missing> |
| 72 | + </RevisionBlock> |
| 73 | + makes a copy of the variadic function arguments |
| 74 | + </Desc> |
| 75 | + <Desc kind="function macro"> |
| 76 | + <Fragment slot="item"> |
| 77 | + <Missing>va_end</Missing> |
| 78 | + </Fragment> |
| 79 | + ends traversal of the variadic function arguments |
| 80 | + </Desc> |
| 81 | + <Desc kind="typedef"> |
| 82 | + <Fragment slot="item"> |
| 83 | + <Missing>va_list</Missing> |
| 84 | + </Fragment> |
| 85 | + holds the information needed by <Missing>`va_start`</Missing>, <Missing>`va_arg`</Missing><Revision since="C++11">, <Missing>`va_copy`</Missing></Revision>, and <Missing>`va_end`</Missing> |
| 86 | + </Desc> |
| 87 | +</DescList> |
| 88 | +
|
| 89 | +The behavior of the <Missing>`va_start`</Missing> macro is <Behavior kind="undef">undefined</Behavior> if the last parameter before the ellipsis has reference type, or has type that is not <DocLink src="/c/language/compatible_type">compatible</DocLink> with the type that results from default argument promotions. |
| 90 | +
|
| 91 | +<RevisionBlock since="C++11"> |
| 92 | + If the a <DocLink src="/cpp/language/parameter_pack">pack expansion</DocLink> or an entity resulting from a <DocLink src="/cpp/language/lambda">lambda capture</DocLink> is used as the last parameter in <Missing>`va_start`</Missing>, the program is <Behavior kind="ifndr">ill-formed, no diagnostic required</Behavior>. |
| 93 | +</RevisionBlock> |
| 94 | +
|
| 95 | +<div {...autoRev({ autorevSince: "C++11" })}> |
| 96 | + ## Alternatives :badge[C++11] |
| 97 | +
|
| 98 | + - <DocLink src="/cpp/language/parameter_pack">Variadic templates</DocLink> can also be used to create functions that take variable number of arguments. They are often the better choice because they do not impose restrictions on the types of the arguments, do not perform integral and floating-point promotions, and are type safe. |
| 99 | + - If all variable arguments share a common type, a <Missing>`std::initializer_list`</Missing> provides a convenient mechanism (albeit with a different syntax) for accessing variable arguments. In this case however the arguments cannot be modified since <Missing>`std::initializer_list`</Missing> can only provide a const pointer to its elements. |
| 100 | +</div> |
| 101 | +
|
| 102 | +## Notes |
| 103 | +
|
| 104 | +In the C programming language until C23, at least one named parameter must appear before the ellipsis parameter, so `R printz(...);` is not valid until C23. In C++, this form is allowed even though the arguments passed to such function are not accessible, and is commonly used as the fallback overload in <DocLink src="/cpp/language/sfinae">SFINAE</DocLink>, exploiting the lowest priority of the ellipsis conversion in <DocLink src="/cpp/language/overload_resolution">overload resolution</DocLink>. |
| 105 | +
|
| 106 | +This syntax for variadic arguments was introduced in 1983 C++ without the comma before the ellipsis. When C89 adopted function prototypes from C++, it replaced the syntax with one requiring the comma. For compatibility, C++98 accepts both C++-style `f(int n...)` and `C-style f(int n, ...)`. The original C++-style grammar is deprecated since C++26. |
| 107 | +
|
| 108 | +<RevisionBlock since="C++20" vertical> |
| 109 | + The comma can be used in abbreviated function templates to make the ellipsis signify a variadic function instead of a variadic template: |
| 110 | +
|
| 111 | + ```cpp |
| 112 | + void f1(auto...); // same as template<class... Ts> void f3(Ts...) |
| 113 | + void f2(auto, ...); // same as template<class T> void f3(T, ...) |
| 114 | + ``` |
| 115 | +</RevisionBlock> |
| 116 | + |
| 117 | +## Defect reports |
| 118 | + |
| 119 | +The following behavior-changing defect reports were applied retroactively to previously published C++ standards. |
| 120 | + |
| 121 | +<DRList> |
| 122 | + <DR kind="cwg" id={506} std="C++98"> |
| 123 | + <Fragment slot="behavior-published"> |
| 124 | + passing non-POD class arguments to an ellipsis resulted in undefined behavior |
| 125 | + </Fragment> |
| 126 | + <Fragment slot="correct-behavior"> |
| 127 | + passing such arguments is conditionally-supported with implementation-defined semantics |
| 128 | + </Fragment> |
| 129 | + </DR> |
| 130 | + |
| 131 | + <DR kind="cwg" id={634} std="C++98"> |
| 132 | + <Fragment slot="behavior-published"> |
| 133 | + conditionally-supported class types made some SFINAE idioms not work |
| 134 | + </Fragment> |
| 135 | + <Fragment slot="correct-behavior"> |
| 136 | + always supported if unevaluated |
| 137 | + </Fragment> |
| 138 | + </DR> |
| 139 | + |
| 140 | + <DR kind="cwg" id={2247} std="C++11"> |
| 141 | + <Fragment slot="behavior-published"> |
| 142 | + no restriction on passing parameter pack or lambda capture to `va_start` |
| 143 | + </Fragment> |
| 144 | + <Fragment slot="correct-behavior"> |
| 145 | + made ill-formed, no diagnostic required |
| 146 | + </Fragment> |
| 147 | + </DR> |
| 148 | + |
| 149 | + <DR kind="cwg" id={2347} std="C++11"> |
| 150 | + <Fragment slot="behavior-published"> |
| 151 | + it was unclear whether scoped enumerations passed to an ellipsis are subject to default argument promotions |
| 152 | + </Fragment> |
| 153 | + <Fragment slot="correct-behavior"> |
| 154 | + passing scoped enumerations is conditionally-supported with implementation-defined semantics |
| 155 | + </Fragment> |
| 156 | + </DR> |
| 157 | +</DRList> |
| 158 | + |
| 159 | +## See also |
| 160 | + |
| 161 | +<DescList> |
| 162 | + <Desc> |
| 163 | + <DocLink slot="item" src="/c/language/variadic"> C documentation</DocLink> for <span> **Variadic arguments** </span> |
| 164 | + </Desc> |
| 165 | + <Desc> |
| 166 | + <DocLink slot="item" src="/c/language/conversion"> C documentation</DocLink> for <span> **Implicit conversions** </span> |
| 167 | + </Desc> |
| 168 | +</DescList> |
0 commit comments