42

I am used to declaring variadic functions like this:

int f(int n, ...);

When reading The C++ Programming Language I found that the declarations in the book omit the comma:

int f(int n...); // the comma has been omitted

It seems like this syntax is C++ specific as I get this error when I try to compile it using a C compiler:

test.c:1:12: error: expected ‘;’, ‘,’ or ‘)’ before ‘...’ token int f(int n...);

Is there any difference between writing int f(int n, ...) and int f(int n...)?

Why was this syntax added C++?

wefwefa3
  • 3,872
  • 2
  • 29
  • 51
  • 2
    http://en.cppreference.com/w/cpp/utility/variadic – knivil Feb 29 '16 at 19:37
  • 1
    [Another reference](http://en.cppreference.com/w/cpp/language/variadic_arguments) that describes this peculiarity. Look at the bottom of the page regarding `printz(...)`. – callyalater Feb 29 '16 at 19:38
  • 1
    I believe that this feature was added in C++ because of the *operator* nature of `...`. This allowed for more consistent syntax in the language with added features like [parameter packs](http://en.cppreference.com/w/cpp/language/parameter_pack). – callyalater Feb 29 '16 at 19:51
  • 2
    @callyalater This... "feature"... predates C++11. You can see the relevant rule still in [N1905](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1905.pdf) – Barry Feb 29 '16 at 21:08
  • 1
    @Barry, I thought that parameter packs were discussed pre-C++11, but never included and the ellipsis operator was an included part to ease in the transition if/when added later. I looked at the standard, but I was under the impression that it was included as part of a concession for later development. – callyalater Feb 29 '16 at 21:13
  • 3
    `I am used to declaring variadic functions like this`: I hope you don't do that on a regular basis. Writing such functions regularly crushes the type safety of your program and opens up huge oppertunities for programmer driven bugs. – Sebastian Mach Mar 01 '16 at 09:26
  • Related [What are the 6 dots in template parameter packs?](https://stackoverflow.com/a/33502576/1708801) – Shafik Yaghmour Dec 08 '17 at 07:18

4 Answers4

37

According to § 8.3.5.4 of the C++ standard (current draft):

Where syntactically correct and where “...” is not part of an abstract-declarator, “, ...” is synonymous with “...”.

In short, in C++ ... (ellipsis) is an operator in its own right and so can be used without the comma, but use of the comma is retained for backwards compatibility.

Barry
  • 286,269
  • 29
  • 621
  • 977
kfsone
  • 23,617
  • 2
  • 42
  • 74
  • 11
    ... and, in my view, for clarity. `int n...` looks like it should have something to do with parameter pack expansion. Or, at the very least, it looks like the `...` is related to the `n`. – Lightness Races in Orbit Feb 29 '16 at 20:29
  • @PreferenceBean In all fairness it probably predates parameter pack expansion (C++11). – Pharap Mar 01 '16 at 01:05
  • @Pharap: It 100% does but that doesn't change what I said! – Lightness Races in Orbit Mar 01 '16 at 01:07
  • 1
    @PreferenceBean I never said it did. The point is that they weren't thinking of that back then because parameter pack expansion wasn't a thing. Until five years ago, the paramater pack thing wouldn't have been an issue. Understanding the history of a language is important because it helps to explain these little obscurities. – Pharap Mar 01 '16 at 01:16
  • 2
    @Pharap What was the possible purpose of allowing the omission of the comma? – Barry Mar 01 '16 at 01:56
  • 1
    @Barry Presumably because somebody thought it was a good idea somewhere along the line. That's one of those questions only the people who accepted it into the spec could answer. If I had to guess I'd have to say to make it appear more like the use of ellipses in language or simply because it's a fraction of a second quicker to write. – Pharap Mar 01 '16 at 05:23
  • 1
    @Barry because that's the wrong question. What was the possible reason for *adding* an unnecessary comma? See my answer for historical overview. – JDługosz Mar 01 '16 at 14:03
  • @Pharap look at the grammar. `...` is not a parameter declaration so it doesn't naturally appear as a member of a comma separated list of declarations. It's a separate production of its own. The comma has to be included in that production explicitly, different from the production that forms the list of parameters. – JDługosz Mar 01 '16 at 14:07
  • @JDługosz When I say 'language' I mean conversational/natural language (like English), not a programming language (like C). In most languages of the world, ellipses are understood to mean 'et cetera', which would match its use here. And when I say quicker to write, I mean for the end-programmer, not the people writing the compiler. Either way, I'm just guessing, I'm not claiming to know the answer. As I said before, only the people actually writing and accepting the spec would know why it was added. – Pharap Mar 01 '16 at 14:23
  • Writing and accepting the spec: this was *long* before there was any such formal process. One guy just did it and presented it to his friends to use. Declaration of function parameters was literally one of the first things in the language, before the name "C++" was coined. I do know that he used formal tools for making the parser, *not* a hand-rolled recursive descent parser. – JDługosz Mar 02 '16 at 00:42
  • The question is "Why was this syntax added C++?" , not "Is this valid in C++?". Also, `...` is not an operator. An operator operates on expression(s) to yield another expression. – M.M Mar 02 '16 at 01:31
  • You should be explicit and not say "current" since people will read this in the future. – JDługosz Mar 02 '16 at 15:25
  • Please don't just add my answer to your answer. – Barry Mar 03 '16 at 12:57
29

Currently, both of these declarations have the same meaning:

int f(int n, ...);
int f(int n ...);

This leads to an issue where the following two declarations are both legal, yet have wildly different meanings:

template <class... T> void f(T...); // function template with parameter pack
template <class T> void f(T...);    // variadic function

Once C++11 introduced variadic templates, it is much more likely that the second declaration is a programmer error rather than lazily omitting the comma. As a result, there was a proposal to remove the latter from the language (P0281), but it was apparently rejected.

Community
  • 1
  • 1
Barry
  • 286,269
  • 29
  • 621
  • 977
  • Very interesting to note. But I disagree with your characterization as "lazy omittion". Not having it has *always* been the normal case. An extra comma is defined as a synonym, for compatibility with C declarations, or perhaps you add it to look better. But it's something *added* not something *omitted*. – JDługosz Mar 01 '16 at 14:01
  • The proposal was rejected in EWG on tuesday. – Cubbi Mar 03 '16 at 14:36
  • @Cubbi ::sad panda:: – Barry Mar 03 '16 at 14:38
15

With int f(int n, ...); and int f(int n...);, as you can see, both , ... and ... has the same meaning. Comma is optional.

But this int printz(...); is valid in C++ while int printz(,...); is not (at least one named parameter must appear before the ellipsis parameter). That's why you can have just (...), even though the arguments passed to such function are not accessible.

hlscalon
  • 7,304
  • 4
  • 33
  • 40
6

As I recall from the time, C++ indeed defined variadic function signatues as you note. Later, the rapidly evolving C language (on the journey from K&R to ANSI) introduced prototypes or new-style function declarations that also declared parameters inside parens after the function name. But, with two notable differences: the comma before the ellipses, and the need for the abomination of (void) to indicate an empty parameter list (to preserve backward compatibility of the empty parens as an old style declaration).

Looking through my archives, I find The C++ Programming Language original edition "reprinted with corrections July 1987" shows:

    argument-declaration-list:
        arg-declaration-listopt
...opt

    arg-declaration-list:
       arg-declaration-list
, argument-declaration
       argument-declaration

There is no form to accept the now-optional comma. Note that the arg-declaration-list is a comma-separated and this doesn't hang out to provide a comma after the list and before the next (different) thing.

This is the most natural way to write this. If you want a comma, you need explicitly , ... in the first production, as two distinct (possibly whitespace separated) tokens.

As C's efforts to proper standardization progressed, C++ compilers started accepting the C versions as well to allow easy use of the C standard header files.

Why did the C designers add the comma when it implies a less sensible grammatical role of the ellipses as a fake parameter placeholder? I never found out.

JDługosz
  • 5,592
  • 3
  • 24
  • 45
  • So your argument is that the comma is bad because it makes the grammar rules [slightly] harder to write? – Barry Mar 02 '16 at 14:28
  • No, that's not the point and the observation indicates that the point is missing. It's the same as the exclaimation point: it was never needed and not designed in. So why would you suppose that "leaving it out" is even a thing? – JDługosz Mar 02 '16 at 15:24