The C++11 standard explicitly makes va_list
and the supporting macros available through <cstdarg>
(§18.10, table 37) but makes no attempt to restrict their use or (re)define their meaning, so I'm going to turn to the C standard.
§7.15.1.4 says that:
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 , ...
). 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.
In your case, format_
is not an argument (it's a captured variable in your lambda) and the function in which va_start
is called is not even the one with the variable parameter list, so you're arguably very much in the realm of undefined behavior. Not to mention that the argument promotion rules of the C language can't deal with reference types, and therefore it can't correctly deal with the fact that format_
is a reference, not a straight-up pointer.
As far as I know, it's syntactically infeasible to use variadic parameters in a constructor's initializer list. (See this guy below who did it.) You could, however, use variadic templates to forward the parameters to a "clean" C-style variadic parameters function:
#include <cstdarg>
#include <cstdio>
#include <string>
std::string stringprintf(const char* format, ...)
{
char buffer[0x2000];
va_list ap;
va_start(ap, format);
vsnprintf(buffer, sizeof buffer, format, ap);
va_end(ap);
return buffer;
}
class ArgumentException : public std::runtime_error
{
public:
template<typename... T>
ArgumentException(const char* format, T... arguments)
: std::runtime_error(stringprintf(format, arguments...))
{ }
};
Also consider using <stdexcept>
's invalid_argument
exception subclass.