Generally, using the C++11 variadic template feature with functions requires the variadic-based function arguments to be the last in the function argument list. There is one exception; they are the next-to-last arguments if there are C-level variadic arguments, which must be dead last.
template < typename ...Args >
int super_printf( Something x, Args &&...a, ... );
I sometimes randomly think about C++, and I wondered how such a function can be implemented. I first thought about the usual recursive peeling of arguments from a, then I remembered that the C-level varargs don't cascade. I have to turn them to a definitive va_list right away.
template < typename ...Args >
int super_vaprintf( Something x, std::va_list &aa, Args &&...a );
// Note that "aa" is passed by reference.
template < typename ...Args >
int super_printf( Something x, Args &&...a, ... )
{
std::va_list args2;
int result;
va_start( args2, XXX ); // (A)
try {
result = super_vaprintf( x, args2, std::forward<Args>(a)... );
} catch ( ... ) {
va_end( args2 ); // (1)
throw;
}
va_end( args2 ); // (2)
return result;
// Can (1) and (2) be compacted with RAII using a custom deleter lambda
// in std::unique_ptr or something? Remember that "va_end" is a macro!
}
The usual C++ variadic recursive peeling happens in the super_vaprintf
call. At line (A), what goes in the place of XXX
, "a" or "a..."? What happens if a is empty, does x go there instead? If that last question's true, are we screwed if there's no x; that there's no arguments besides the variadic ones? (And if it's true, how do we conditionalize the code to use x when a is empty, and a otherwise?)
...
I just looked at my copy of the C++11 standard for any assistance here. There doesn't seem to be any. This would prompt a request for the C++ committee to come back to fix this, but I'm not sure that there's any way such a function could be called without the C++ varargs taking everything. Am I wrong; can a function call be made to use both C++ and C varargs? Or is mixing only useful for declarations, in terms of Stupid (Template) Instantiation Tricks?
It takes one fixed argument and then any number of arguments can be passed. The variadic function consists of at least one fixed variable and then an ellipsis(…) as the last parameter. This enables access to variadic function arguments. *argN* is the last fixed argument in the variadic function.
In Swift, variadic parameters are the special type of parameters available in the function. It is used to accept zero or more values of the same type in the function. It is also used when the input value of the parameter is varied at the time when the function is called.
Variadic functions are functions (e.g. printf) which take a variable number of arguments. The declaration of a variadic function uses an ellipsis as the last parameter, e.g. int printf(const char* format, ...);.
When you call a function whose last parameter is a pack, all the arguments become part of that pack. There is nothing left for va_args
. Your usage of explicit template arguments is misleading because they are not exclusive; they simply precede implicit arguments.
To defeat deduction, you need a reference:
(& super_printf<int, int>) ( 0L, 1, 2, 3, 4, 5 )
This is fairly contrived, but now you have the problem of nothing to pass to va_start
.
To provide a reasonable interface to users, just add a parameter between the two lists.
struct va_separator {}; // Empty; ABI may elide allocation.
template < typename ...Args >
int super_printf( Something x, Args &&...a, va_separator, ... );
This super_printf
will need both explicit arguments to define the pack and an explicit separator argument. But you can alternatively provide a public function which receives all its arguments by pack, then finds the separator and forwards to super_printf
using an explicit argument list comprising the pack elements before the separator.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With