Historically, the ellipsis syntax ...
comes from C.
This complicated beast was used to power printf
-like functions and is to be used with va_list
, va_start
etc...
As you noted, it is not typesafe; but then C is far from being typesafe, what with its implicit conversions from and to void*
for any pointer types, its implicit truncation of integrals/floating point values, etc...
Because C++ was to be as close as possible as a superset of C, it inherited the ellipsis from C.
Since its inception, C++ practices evolved, and there has been a strong push toward stronger typing.
In C++11, this culminated in:
- initializer lists, a short-hand syntax for a variable number of values of a given type:
foo({1, 2, 3, 4, 5})
- variadic templates, which are a beast of their own and allow writing a type-safe
printf
for example
Variadic templates actually reuse the ellipsis ...
in their syntax, to denote packs of types or values and as an unpack operator:
void print(std::ostream&) {}
template <typename T, typename... Args>
void print(std::ostream& out, T const& t, Args const&... args) {
print(out << t, args...); // recursive, unless there are no args left
// (in that case, it calls the first overload
// instead of recursing.)
}
Note the 3 different uses of ...
:
typename...
to declare a variadic type
Args const&...
to declare a pack of arguments
args...
to unpack the pack in an expression
void foo(double *)
and call it byfoo((double[]){1,2,3,4,5})
. Need GNU C++ extension. – Equitiesvoid foo(double ..., int ..., double ...)
and the like. – Sycaminetemplate<class T> using id = T; void foo(double*); foo(id<double[]>{1,2,3,4});
works fine w/o extensions. – Disincentiveconst char*
describing the parameters and compilers could choose the passing means as appropriate, so givenint a; long b; print(1, 0x12345, a, b, a+b)
a compiler could generate a temp holdinga+b
, and pass astatic const char[]
containing, encoded, the integer value 1, the integer value 0x12345, the static or frame-relative address of a, the static or frame-relative address of b, and the frame-relative... – Abbyabbyeint
to two bytes (or maybe even one) if the variable was near the top of the stack frame, as would often be the case. – Abbyabbye