In the C++03 standard, [dcl.fct] p.2 states that:
The parameter-declaration-clause determines the arguments that can be specified, and their processing, when the func- tion is called. [ Note: the parameter-declaration-clause is used to convert the arguments specified on the function call; see5.2.2. —endnote]Iftheparameter-declaration-clauseisempty,thefunctiontakesnoarguments.Theparameter list (void) is equivalent to the empty parameter list. Except for this special case, void shall not be a parameter type (though types derived from void, such as void*, can). If the parameter-declaration-clause terminates with an ellipsis, the number of arguments shall be equal to or greater than the number of parameters that do not have a default argument. Where syntactically correct, “, ...” is synonymous with “...”.
The grammar for a parameter-declaration-clause allows it to end in either ... or , .... I found this question and the answers said that initially the grammar allowed only ..., and the comma variant (, ...) was introduced for compatibility with C.
My question is why does the quoted paragraph say "where syntactically correct"? Considering that function parameter packs or pack expansions were not present in C++03, are there any cases where it would be "syntactically incorrect" to consider ... synonymous with , ...?
Thank you.
for my understanding, it just mean that when you use ,... with a correct syntax, then it can be replaced by ...
for instance :
int printf(const char*, ...); is a correct syntax and can be replaced by int printf(const char*...);
int printf(,...); is not syntactically correct and is not equivalent to int printf(...);
You can easily try in a C code by just adding the following prototypes:
void printf(...); --> works
void printf(,...); --> expected primary-expression before ‘,’ token
are there any cases where it would be "syntactically incorrect" to consider ... synonymous with , ...?
Exactly as Guillaume says, it would be "syntactically incorrect" to rewrite
foo(...)
as
foo(, ...)
so that clause just handles the corner case where there is no prior parameter from which the ellipsis can be separated by a comma.
Related
template<typename... T>
void foo(T... args);
In the above example, T is expanded according to §14.5.3 - (4.1) of the standard.
§14.5.3 - (4.1) — In a function parameter pack (8.3.5); the pattern is the parameter-declaration without the ellipsis.
What exactly is happening here? Let's say I call the function with 3 integers.
foo(1, 2, 3);
Is the parameter pack being expanded like
foo(int arg1, int arg2, int arg3);
where arg1, arg2, and arg3 are just arbitrary names given to by the compiler?
The standard says how "the pattern is the parameter-declaration without the ellipsis"
The other way I interpret that is args gets a single parameter-declartion.Is args getting its own type? I've tried doing
std::cout << typeid(args).name;
but that doesn't work, and throws compiler errors. So I could assume it's not getting its own type. Could someone "dumb down" what really is happening here, and the behavior of the function parameter pack?
Alright, I think I've figured it out. Correct me if I'm wrong.
A parameter expansion happens when the ellipsis is on the right on the pattern. Our pattern here is simply just T:
foo(T... args);
The standard states that the result of this will be a parameter-declaration. This decays into:
attribute-specifier-seqopt decl-specifier-seq declarator
attribute-specifier-seq can be ignored.
decl-specifier-seq is the type, T;
declarator is ... args
Semantically, this is a function parameter pack declaration. Nothing special.
Once again, my curiosity causes me to go insane for a little... heh.
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++?
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.
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.
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.
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.
When compiling in C++ I often end up with error messages dealing with "formal parameters", such as
error C2719: 'b': formal parameter with __declspec(align('16')) won't be aligned
I do understand the error, and the fact that b is a parameter of a function I am defining.
However, what does it mean that a parameter is formal? Can there be informal parameters as well?
I do notice that the term "formal parameter" appears in other languages as well, so I presume it is a more generic term not necessarily specific to C-family of languages? Are informal parameters supported by some subset of languages?
Upon seeing the answers, one final question: Where those names formal parameter and actual parameter origin from? Does it origin from the C standard, or is it an effect of calling it as such in some abstract language calculus?
There are formal and actual parameters:
void foo(int arg); //arg is a formal parameter
int main()
{
int val = 1;
foo(val); //val is an actual parameter
}
From C++ Standard:
1.3.1 formal parameter (parameter)
an object or reference declared as part of a function declaration or
definition, or in the catch clause of an exception handler, that
acquires a value on entry to the function or handler; an identifier
from the comma-separated list bounded by the parentheses immediately
following the macro name in a function-like macro definition; or a
template-parameter. Parameters are also known as formal arguments or
formal parameters.
1.3.10 actual parameter (argument)
an expression in the comma-separated list bounded by the parentheses
in a function call expression, a sequence of preprocessing tokens in
the comma-separated list bounded by the parentheses in a function-like
macro invocation, the operand of throw, or an expression, type-id or
template-name in the comma-separated list bounded by the angle
brackets in a template instantiation. Also known as an actual argument
or actual parameter.
Formal parameters are the parameters known at the function definition. The actual parameters are what you actually (hence the name) pass to the function when you call it.
void foo( int a ); // a is a formal parameter
foo(10); // 10 is the actual parameter
It's a matter of being a little pedantic over terminology, but quite useful: The formal parameters are what you just think of function parameters:
int foo(bool a, float b);
Here a and b are formal parameters. The point is that in the function body, you're referring to those parameters "formally" without actually knowing their value. It is only when you actual evaluate a function call expression that the formal function parameters are bound to the function call arguments:
int result = foo(false, 1.5);
In this call expression, the value false of the first argument is bound to the formal parameter a, and similarly for the second argument.
The distinction between parameters and arguments is maybe more important to language designers and comiler writers, but as an example in C++, it can be very helpful to get your head around this when you're trying to follow the rules for template argument deduction.
In C++11 the following function declaration:
int f(void);
means the same as:
int f();
A parameter list consisting of a single unnamed parameter of non-dependent type void is equivalent to an empty parameter list.
I get the (perhaps false) impression this is an old feature, perhaps inherited from C?
Does anyone know the history or rationale behind this way to declare a function with no parameters?
In C++ they both mean the same thing.
In C f(void) is different from f(), becuse f() means "unspecified parameters" - you can legally pass anything (whether the function at receiving the data is happy about that or not is another matter).
In C++ both are the same thing.
In C, f() means that we don't know how many parameters the function takes at this point. It is unspecified parameters. And f(void) means that this function does not take any parameters.
From the C standard :
6.7.6.3 Function declarators (including prototypes)
6/ A parameter type list specifies the types of, and may declare identifiers for, the
parameters of the function.
10/ The special case of an unnamed parameter of type void as the only item in the list
specifies that the function has no parameters.
14/ An identifier list declares only the identifiers of the parameters of the function. An empty list in a function declarator that is part of a definition of that function specifies that the function has no parameters. The empty list in a function declarator that is not part of a definition of that function specifies that no information about the number or types of the parameters is supplied.
And like you said, in the C++ standard :
8.3.5 Functions [dcl.fct]
4/ The parameter-declaration-clause determines the arguments that can be specified, and their processing, when the function is called. [ Note: *the parameter-declaration-clause* is used to convert the arguments specified on the function call; see 5.2.2. —end note ] If the parameter-declaration-clause is empty, the function takes no arguments. A parameter list consisting of a single unnamed parameter of non-dependent type void is equivalent to an empty parameter list.
This comes to C++ from C. In C f() means unknown number and type of parameters. So in C for no parameters there is f( void ).
In C++ it's redundant: f() and f( void ) mean same thing - a function that has no parameters.
From "A History of C++" (1979− 1991 by Bjarne Stroustrup) at p11:
C with Classes introduced the notation f(void) for a function f that
takes no arguments as a contrast to f() that in C declares a function
that can take any number of arguments of any type without any type
check.
It says later, however, that soon the empty function declarator was given its obvious meaning and the new construct - kinda rendered obsolete for the time. I guess nobody has bothered removing it after (or maybe there had been already some C++ code written with it that have needed support).
In C:
This construct however rendered important role as of the standardization of the C language where function prototyping was borrowed directly from C++. In this case f(void) was useful in supporting existing C code (in which the notion f() was already reserved as to indicate a function taking unspecified number of arguments).
Before that the C language hadn't been able to attach specific types to each parameter but only functions with unspecified number of arguments and with unspecified types were declarable using the f() form.
In C++, there is no difference. However, this is inherited from C, where int f() mean "function which can take any number of arguments of any types" and int f(void); specifies functions that takes no arguments.
Edit As Angew pointed out, in C, f() means "function whose parameters are unknown at this point." It does not mean it can take any number of arguments - close to that would be f(T arg, ...), where arg is at least one named parameter before ..., which accepts at least one argument, arg (as pointed by #hvd).
I answered this question How can I get my va_list arguments to repeat itself? and noticed the uncommon function declaration:
void ordered(int num1, double list ...);
First i thought the compiler would complain but clang 3.2 didn't and neither did g++ 4.7.2.
What does this declaration expand to? As what does it get interpreted?
Edit: I know about the ellipsis. But the normal form is <return type> <function-name>(<argument1-type> <arg-name>, ...); in the example the comma is missing.
It's the same as:
void ordered(int num1, double list, ...);
This is a snippet of the grammar in the C++ standard:
parameter-declaration-clause:
parameter-declaration-list[opt] ...[opt]
parameter-declaration-list , ...
Basically the ellipsis can be preceded by , if the are other parameter declarations, but it need not be. The function declaration:
void f(int,double...);
really means:
void f(int,double,...);
void ordered(int num1, double list ...);
is same as:
void ordered(int num1, double list, ...);
Reference:
Standard C++11 8.3.5.3/4:
parameter-declaration-clause:
parameter-declaration-listopt ...opt
parameter-declaration-list , ...
If the parameter-declaration-clause terminates with an ellipsis or a function parameter pack (14.5.3), the number of arguments shall be equal to or greater than the number of parameters that do not have a default argument and are not function parameter packs. Where syntactically correct and where “...” is not part of an abstract-declarator, “, ...” is synonymous with “...”.
The three dots (...) are called "ellipses" and denote a variable argument list. So you can pass as many arguments as you like (there is an OS-specified limitation, though). In this way, printf works, for example.
See here for further explanation.
I guess you mean the "..." right?
For some functions it is not possible to specify the number and type of all arguments expected in a call. Such a function is declared by terminating the list of argument declarations with the ellipsis (...).