trato de evitar el uso de las funciones de c-estilo var-arg por dos razones principales:
- No son de tipo seguro, no puede utilizar el operador < <
- No reconocen cuando se proporcionaron muy pocos o muchos argumentos
He hecho una forma que funciona usando boost::fusion
, que se da argumentos de forma segura. Se repite sobre esos argumentos, imprimiéndolos cuando se encuentra un %
. Si se dieron demasiados o demasiados argumentos, se lanza una excepción.
Todavía hay un problema: las macros variables no son aún estándar en C++. Entonces, he hecho dos versiones. Uno que funciona con C++ actual. Tiene que invocarlo usando
dprintf("name: %, value: %\n", ("foo", 42));
Luego. La otra versión, el uso de macros variadic, se puede utilizar mediante la definición de un símbolo de preprocesador, que le permite escribir
dprintf("name: %, value: %\n", "foo", 42);
Aquí está el código. El boost.fusion
proporciona más detalles sobre esto,
#include <boost/fusion/include/sequence.hpp>
#include <boost/fusion/include/make_vector.hpp>
#include <boost/fusion/include/next.hpp>
#include <stdexcept>
#include <iostream>
template<typename IterS, typename IterSeqE>
void print_vec(IterS b, IterS e, IterSeqE, IterSeqE) {
while(b != e) {
if(*b == '%') {
if(++b != e && *b == '%') {
std::cout << '%';
} else {
throw std::invalid_argument("too many '%'");
}
} else {
std::cout << *b;
}
++b;
}
}
template<typename IterS, typename IterSeqB, typename IterSeqE>
void print_vec(IterS b, IterS e, IterSeqB seqb, IterSeqE seqe) {
while(b != e) {
if(*b == '%') {
if(++b != e && *b == '%') {
std::cout << '%';
} else {
std::cout << *seqb;
return print_vec(b, e, next(seqb), seqe);
}
} else {
std::cout << *b;
}
++b;
}
throw std::invalid_argument("too few '%'");
}
template<typename Seq>
void print_vec(std::string const& msg, Seq const& seq) {
print_vec(msg.begin(), msg.end(), begin(seq), end(seq));
}
#ifdef USE_VARIADIC_MACRO
# ifdef DEBUG
# define dprintf(format, ...) \
print_vec(format, boost::fusion::make_vector(__VA_ARGS__))
# else
# define dprintf(format, ...)
# endif
#else
# ifdef DEBUG
# define dprintf(format, args) \
print_vec(format, boost::fusion::make_vector args)
# else
# define dprintf(format, args)
# endif
#endif
// test, using the compatible version.
int main() {
dprintf("hello %, i'm % years old\n", ("litb", 22));
}
No puedo hablar de otros compiladores, pero para GCC, -What y __attribute __ ((format)) son sus amigos. Eso permite API de estilo printf con todas las bondades de verificación de tipo del operador <<. – Tom
sí, soy consciente de esos atributos. pero no te permitirá pasar tus propios tipos. por ejemplo, puede usar una lista. y quiere sobrecargar el operador << para su lista. con printf, debe escribir el mismo ciclo nuevamente y está limitado a ciertos tipos de elementos que printf entiende. –
operador de sobrecarga << permite poner el código de impresión en el lado del tipo que desea imprimir, que prefiero poner el código de impresión al costado de mi código de depuración.por lo tanto, cada vez que tenga algo imprimible, su solución dprintf de tipo seguro ya lo entiende. –