Function with a variable number of parameters without any explicit parameters - c++

How to work in C++ with functions the following form: void function(...) {}?
Do really need at least one implicit parameter?

Repeating from a comment:
It seems there is an interesting difference between C99 and C++11 here: C++11 allows a function declaration void foo(...) because the parameter-declaration-list in the parameter-declaration-clause is optional: [dcl.fct]
Function declaration:
D1 ( parameter-declaration-clause ) cv-qualifier-seqopt ref-qualifieropt exception-specificationopt attribute-specifier-seqopt
Parameters:
parameter-declaration-clause:
  parameter-declaration-listopt ...opt
  parameter-declaration-list , ...
(Note how both the parameter-declaration-list and the ... are separately opt here, meaning you can leave out one or the other or both. This interpretation is supported by clang++ and g++.)
In C99, this declaration is not allowed since the parameter-list is not optional in the parameter-type-list: 6.7.5/1
Function declaration:
direct-declarator ( parameter-type-list )
Parameters:
parameter-type-list:
  parameter-list
  parameter-list , ...
As the va_start etc. macros/functions are inherited from C99, there's no way to use the arguments matched with the ellipsis with an empty parameter-declaration-list in C++.
Description of va_start in C99: 7.15.1.4
void va_start(va_list ap,parmN);
[...]
The parameter parmN is the identifier of the rightmost parameter in the variable
parameter list in the function definition (the one just before the , ...). [...]
Emphasis mine. C99 assumes there's a parameter before the ellipsis, because it isn't legal in C99 to declare a function with an ellipsis but without parameters.
Yet, I can see two reasons to use a function with an ellipsis but w/o any parameters in C++:
Overload resolution. Matching arguments to an ellipsis leads to a very low ranking of the overload: An ellipsis conversion sequence is worse than any user-defined and standard conversion sequence [over.ics.rank]/2. This can be useful for metaprogramming:
char foo(int);
int foo(...);
struct S{};
S s;
sizeof(foo(42)); // yields 1
sizeof(foo(s)); // yields sizeof(int)
Implementation-defined tricks. Your implementation may provide a mean to access those arguments matched with an ellipsis. E.g. see BobTFish's example

If you want to maintain some semblance of platform independence, you need at least one parameter and use the va_arg macros.
If you know the low level details of the architecture and calling convention, then you can pull the arguments directly out of the registers and/or stack (depending on where the various parameters end up).

Given that the va_start "function" requires an argument to set up the va_list, I'd say it's not possible to do this in a way that works reliably and portably. It may well be possible to find something that works on specific platforms - but don't expect it to work if you change the compiler, compile for a different platform, and in some cases even if you compile with different compiler options (or change the code in the function, e.g. introducing local variables).
...
va_list vl;
va_start(vl, arg);
...
Of course, your other problem is knowing when there is NO arguments (which would be a valid case). So if you don't have at least one argument, what happens when you pass no argument at all? How do you "know" this is the case?

Related

The "(optional)" marker in cppreference.com documentation

Last week, I had a discussion with a colleague in understanding the documentation of C++ features on cppreference.com. We had a look at the documentation of the parameter packs, in particular the meaning of the (optional) marker:
(Another example can be found here.)
I thought it means that this part of the syntax is optional. Meaning I can omit this part in the syntax, but it is always required to be supported by the compiler to comply with the C++ standard. But he stated that it means that it is optional in the standard and that a compiler does not need to support this feature to comply to the standard. Which is it? Both of these explanations make sense to me.
I couldn't find any kind of explanation on the cppreference web site. I also tried to google it but always landed at std::optional...
The opt / (optional) suffix means the symbol is optional [for the C++ programmer to use; not the compiler to support]
As this question has been tagged language-lawyer, and as general when we look for a definite reference, let's move away from CppReference and into the standard.
Where CppReference uses the (optional) subscript, the standard uses opt; e.g. as in [temp.param]/1:
The syntax for template-parameters is:
template-parameter:
type-parameter
parameter-declaration
type-parameter:
type-parameter-key ...opt identifieropt
[... and so on]
[syntax]/1 describe the syntax notation [emphasis mine]:
In the syntax notation used in this document, syntactic categories are
indicated by italic type, and literal words and characters in constant
width type. Alternatives are listed on separate lines except in a few
cases where a long set of alternatives is marked by the phrase “one
of”. If the text of an alternative is too long to fit on a line, the
text is continued on subsequent lines indented from the first one.
An optional terminal or non-terminal symbol is indicated by the subscript “opt", so
{ expressionopt }
indicates an optional expression enclosed in braces.
Thus, you are correct, and your colleague is wrong. Particularly for your example of template parameter packs (which we introduce by the optional ... after typename) the identifier that follows after typename..., which names the pack (or the template parameter, if ... is omitted), is optional.
But he stated that it means that it is optional in the standard and that a compiler does not need to support this feature to comply to the standard.
The ridiculousness of this claim becomes even more clear if we annotate the "optional permutations" of a class template with a single type template parameter:
template<typename>
// ^^^^^^^^ type-parameter
// (omitting optional '...' and 'identifier')
struct S;
template<typename T>
// ^^^^^^^^^^ type-parameter
// (omitting optional '...')
struct S;
template<typename...>
// ^^^^^^^^^^^ type-parameter
// (omitting optional 'identifier')
struct S;
template<typename... Ts>
// ^^^^^^^^^^^^^^ type-parameter
struct S;
If the claim above was true, only the first of these four would need to be supported by a compliant implementation (based solely on grammar, in this contrived example), which would mean a compiler vendor could offer a compliant implementation where we could never name neither template (type) parameters nor function parameters.
It means that particular token is optional. For instance both these declarations work:
template <class... Args>
void foo();
template <class...>
void bar();
While I found a page that lists all of the marks, I was unable to find a page that specifies what the marks are intended to mean. Still, I might ask your colleague to take a look at some other pages, with the goal of the colleague abandoning the idea that "optional" means "optional to support". (This is not a definitive argument, but many would find it persuasive.) I found two good examples at Function declaration.
Function declaration:
noptr-declarator ( parameter-list ) cv(optional) ref(optional) except(optional) attr(optional)
Focus on cv (short for "const-volatile"), which is marked "optional" and which is "only allowed in non-static member function declarations". Your colleague's interpretation of this marker would mean that compilers do not have to support const member functions, as the const keyword is "optional".
Function definition, the first option for function-body:
ctor-initializer(optional) compound-statement
The "optional" part here is the member initializer list (only allowed in constructors). Is your colleague ready to claim that a compiler need not support member initializer lists?
Sometimes one should look at the familiar to understand annotations.

Why are parameters promoted when it comes to a variadic function?

Why are parameters promoted when it comes to a variadic function,for instance floats are promoted to double ext and in which order are they promoted?
Variadic arguments - cppreference.com
Default conversions
When a variadic function is called, after lvalue-to-rvalue, array-to-pointer, and function-to-pointer conversions, each argument that is a part of the variable argument list undergoes additional conversions known as default argument promotions:
std::nullptr_t is converted to void*
float arguments are converted to double as in floating-point promotion
bool, char, short, and unscoped enumerations are converted to int or wider integer types as in integer promotion
Why are parameters promoted
Because that is how the language has been specified.
You may be thinking, why has the language been specified that way. I don't know if there is published rationale for this choice, but I suspect that the answer is as simple as: Because that is how the C language had been specified
You may be thinking, why was the C language specified that way. There is a standard document N1256 discussing design rationale of some choices for the C99 standard. It seems to not cover this choice. Besides, C language existed long before its standardisation and C99 wasn't even the first standard version. This behaviour may have existed before the involvement of the committee.
For what it's worth, same promotion rules apply also to calling functions that haven't been declared (until C99) or calling a fixed argument function through a prototype which doesn't declare the parameters:
// this is C lanugage
void fun();
int main(int, char [][]) {
float f = 42;
fun(f); // argument promotes to double
undeclared(f); // ill-formed since C99
// argument promotes to double prior to C99
The reasons for this may be similar to the reasons for promotion in case of variable parameter lists.
Promotion of arguments for variadic functions make it way more easier to deal with them. Since the function code doesn't know the actual type of arguments from the function signature, calling has to communicate the type through some other means, and promotion reduces the number of options without sacrificing the flexibility.
For example, consider classical example of variadic function - printf. When you give it %f argument, it already knows that the argument is double precision, since it would be promoted. Absence promotion, two different modifiers would have to exist, one for single precision and another one for double precision.
Another example would be integral promotions. Currently any type would work with %d modifier, and while modifiers for short versions do exist, one is not required to use them, and can simplify their code.
In addition, it provides for fewer surprises when using some other variadic functions. For example, Posix open function is shown as if it would be an overloaded function with either 2 or 3 arguments, last argument being specified in the man as mode_t type. In fact, there are no overloads in C, so there are no two versions of open - there is only one, which is a variadic one.
Absent of promotions, one would have to make sure that when 3-argument version is used, the last argument is exactly mode_t type, which would be quite inconvenient, counterintuitive and failure to do so would likely lead to quite unexpected behavior. Automatic promotions save us from this.

Why add void to method parameter list

I've seen methods with the following signature:
void foo (void);
They take no argument, however I'm wondering whether doing this is useful or not. Is there a reason why you would want to do it?
This is a holdover from older versions of C, where foo() meant "a function with an unknown number of parameters" and foo(void) means "a function with zero parameters." In C++, foo() and foo(void) both mean "a function with zero parameters", but some people prefer the second form because it is more explicit.
The C++03 standard says (emphasis mine):
8.3.5.2
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. ] If the
parameter-declaration-clause is empty, the function takes no
arguments.
This means that if you are talking to the compiler it's just a matter of taste.
If you are writing code that will be read by others, then the C++ way of doing things is
void foo();
The other form remains valid only for reasons of compatibility with C, where there was a difference among the two signatures.
In C++ code there is no reason whatsoever to use void in this way. What's more it is very much not the idiomatic way to declare parameterless functions.
This is a legacy from the older versions of C for functions with no arguments.

What's the correct term for the '...' token?

Consider printf:
int printf ( const char * format, ... );
What are the terms used to describe the ... and the functions that use it? I've been calling it an ellipsis, but that's like calling & the "ampersand operator."
Variable length parameter list
Edit:
Or, if describing the function itself: Variadic function
Ellipsis notation (, ...) p202 "K+R The C Programming Language"
"Ellipsis" is in fact often the best term here. Sometimes we refer to "arguments passed using the ellipsis" (C++03 8.3.5p2). In the context of figuring out the best overloaded function, an argument can be said to "match the ellipsis" (C++03 13.3.2p2).
printf and other functions like it are often called "variadic functions".
Note: The coming C++0x Standard offers two different ways of declaring and implementing variadic functions (the va_arg way and the template way). But both involve the ellipsis token.
Ellipsis operator is the only term I have heard - it's rare enough (thankfully) that you don't need anything else!
This C++ draft specification refers to it simply as 'ellipsis' and sometimes with a definite or indefinite article, as 'an ellipsis' or 'the ellipsis'.
5.2.2 "Function call" section 6 contains:
A function can be declared to accept fewer arguments (by declaring
default arguments (8.3.6)) or more arguments (by using the ellipsis, ... 8.3.5)
than the number of parameters in the function definition (8.4).
8.3.5 "Functions" section 2 contains:
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.
8.3.6 section 4 contains sample code:
void g(int = 0, ...); // OK, ellipsis is not a parameter so it can follow
// a parameter with a default argument
Extra pedantry: section 13.3.3.1.3 ("Ellipsis conversion sequences") refers to "the ellipsis parameter specification". However, as stated in the sample code above, the ellipsis is not, strictly speaking, a parameter. 8.3.5 section 1 explains that, while the ellipsis appears in the parameter-declaration-clause, it follows the parameter-declaration-list.
In addition to "ellipsis" and "variadic function", one also sees the terms "vararg" and "varargs" thrown around. This appears to be an abbreviation for "variable argument list", judging by the language surrounding the (LEGACY) header <varargs.h> in POSIX.
Also, the principle reason that the term "ampersand operator" is not used is that the ampersand can represent either of two different operators, depending on the context, which would make the term ambiguous. This does not occur with the ellipsis; there is no other meaning assigned to it, so using the term "ellipsis" for the token "..." is not like using the term "ampersand operator" for the token "&".
Variadic
Martin and Demian are both right:
The three "." together form a ellipsis (On the Macintosh this is a single special character "...", but not usable for C++)
In C++ an ellipsis is used to define a Variable length parameter list

Last named parameter not function or array?

This question is about vararg functions, and the last named parameter of them, before the ellipsis:
void f(Type paramN, ...) {
va_list ap;
va_start(ap, paramN);
va_end(ap);
}
I was reading in the C Standard, and found the following restriction for the va_start macro:
The parameter parmN is the identifier of the rightmost parameter in the variable parameter list in the function definition (the one just before the , ...). If the parameter parmN is declared with the register storage class, with a function or array type, or with a type that is not compatible with the type that results after application of the default argument promotions, the behavior is undefined.
I wonder why the behavior is undefined for the following code
void f(int paramN[], ...) {
va_list ap;
va_start(ap, paramN);
va_end(ap);
}
and not undefined for the following
void f(int *paramN, ...) {
va_list ap;
va_start(ap, paramN);
va_end(ap);
}
The macros are intended to be implementable by pure C code. But pure C code cannot find out whether or not paramN was declared as an array or as a pointer. In both cases, the type of the parameter is adjusted to be a pointer. The same is true for function type parameters.
I wonder: What is the rationale of this restriction? Do some compilers have problems with implementing this when these parameter adjustments are in place internally? (The same undefined behavior is stated for C++ - so my question is about C++ aswell).
The restriction against register parameters or function parameters are probably something like:
you are not allowed to take the address of a variable with the register storage class.
function pointers are sometimes quite different than pointers to objects. For example, they might be larger than pointers to objects (you can't reliably convert a function pointer to an object pointer and back again), so adding some fixed number to the address of a function pointer might not get you to the next parameter. If va_start() and/or va_arg() were implemented by adding some fixed amount to the address of paramN and function pointers were larger than object pointers the calculation would end up with the wrong address for the object va_arg() returns. This might not seem to be a great way to implement these macros, but there might be platforms that have (or even need) this type of implementation.
I can't think of what the problem would be to prevent allowing array parameters, but PJ Plauger says this in his book "The Standard C Library":
Some of the restrictions imposed on the macros defined in <stdarg.h> seem unnecessarily severe. For some implementations, they are. Each was introduced, however, to meet the needs of at least one serious C implementation.
And I imagine that there are few people who know more about the ins and outs of the C library than Plauger. I hope someone can answer this specific question with an actual example; I think it would be an interesting bit of trivia.
New info:
The "Rationale for International Standard - Programming Languages - C" says this about va_start():
The parmN argument to va_start was intended to be an aid to implementors writing the
definition of a conforming va_start macro entirely in C, even using pre-C89 compilers (for example, by taking the address of the parameter). The restrictions on the declaration of the parmN parameter follow from the intent to allow this kind of implementation, as applying the & operator to a parameter name might not produce the intended result if the parameter’s declaration did not meet these restrictions.
Not that that helps me with the restriction on array parameters.
It's not undefined. Keep in mind that when parameter is declared as int paramN[], the actual parameter type will still decay to int* paramN immediately (which is visible in C++, for example, if you apply typeid to paramN).
I must admit that I'm not sure what this bit in the spec is even for, considering that you cannot have parameters of function or array types in the first place (since they will pointer-decay).
I found another relevant quote, from Dinkumware.
The last parameter must not have
register storage class, and it must
have a type that is not changed by the
translator. It cannot have:
* an array type
* a function type
* type float
* any integer type that changes when promoted
* a reference type [C++ only]
So apparently, the problem is precisely that the parameter gets passed in a way different from how it is declared. Interestingly enough, they also ban float and short, even though those should be supported by the standard.
As a hypothesis, it could be that some compilers have problems doing sizeof correctly on such parameters. E.g. it might be that, for
int f(int x[10])
{
return sizeof(x);
}
some (buggy) compiler will return 10*sizeof(int), thus breaking the va_start implementation.
I can only guess that the register restriction is there to ease library/compiler implementation -- it eliminates a special case for them to worry about.
But I have no clue about the array/function restriction. If it were in the C++ standard only, I would hazard a guess that there is some obscure template matching scenario where the difference between a parameter of type T[] and of type T* makes a difference, correct handling of which would complicate va_start etc. But since this clause appears in the C standard too, obviously that explanation is ruled out.
My conclusion: an oversight in the standards. Possible scenario: some pre-standard C compiler implemented parameters of type T[] and T* differently, and the spokesperson for that compiler on the C standards committee had the above restrictions added to the standard; that compiler later became obsolete, but no-one felt the restrictions were compelling enough to update the standard.
C++11 says:
[n3290: 13.1/3]: [..] Parameter declarations that differ only in a
pointer * versus an array [] are equivalent. That is, the array
declaration is adjusted to become a pointer declaration. [..]
and C99 too:
[C99: 6.7.5.3/7]: A declaration of a parameter as ‘‘array of type’’ shall be adjusted to ‘‘qualified pointer to
type’’, where the type qualifiers (if any) are those specified within the [ and ] of the
array type derivation. [..]
And you said:
But pure C code cannot find out whether or not paramN was declared as an array or as a pointer. In both cases, the type of the parameter is adjusted to be a pointer.
Right, so there's no difference between the two pieces of code you showed us. Both have paramN declared as a pointer; there is actually no array type there at all.
So why would there be a difference between the two when it comes to the UB?
The passage you quoted...
The parameter parmN is the identifier of the rightmost parameter in the variable parameter list in the function definition (the one just before the , ...). If the parameter parmN is declared with the register storage class, with a function or array type, or with a type that is not compatible with the type that results after application of the default argument promotions, the behavior is undefined.
...applies to neither, as would be expected.