3

How to work in C++ with functions the following form: void function(...) {}?

Do really need at least one implicit parameter?

17
  • 2
    I highly advise against C variadic functions in C++. Commented Aug 28, 2013 at 15:14
  • 1
    @QueueOverflow, Yes, it needs one parameter before the ellipsis so it can use it to reference where the variadic arguments begin. Commented Aug 28, 2013 at 15:18
  • 1
    You can't think of it as coming "before" the ... in the argument list. It just magically appears. Commented Aug 28, 2013 at 15:22
  • 1
    Yes, but The Standard says nothing about that. And anyway, who says function arguments are always passed on the stack? What about registers? And you still don't know that it will be treated as the "first" parameter. I recall reading somewhere that it is often treated as the "last", but I can't find a reference, so I may be lying. Commented Aug 28, 2013 at 15:27
  • 2
    @BartoszKP, @BoBTFish, I've worked on architectures where the this pointer was always passed in a register. Commented Aug 28, 2013 at 15:53

3 Answers 3

5

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

Sign up to request clarification or add additional context in comments.

2 Comments

@BoBTFish Oops! Good catch!
Thanks for such full answer.
1

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).

Comments

1

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?

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.