I am attempting to write a logging function which takes a variadic argument list and prints in a safe manor.
vprintf seems like the obvious answer, but I cannot seem to find a safe way to handle when the format string expects more arguments than were provided.
Additionally, it would be very nice if I could rearrange the order the parameters are printed.
This second requirement led me to boost::format, which seems to be exactly what I want, except that it does not accept a va_list for input.
I have done some extensive searching and the closest I could get was this solution:
boost::format with variadic template arguments
Unfortunately I am restricted to a specific gcc version which does not seem to include the std::initializer_list
In my searching, I have stumbled upon boost::preprocessor which seems like it should be able to accomplish what I want, but I am struggling with the implementation of it.
So, ideally, what I'm searching for is something that works as follows:
void loggerFunc(const char* msgFormat, ...){
boost::format f(msgFormat);
va_list args;
va_start(args, msg);
f & MagicalFunctionCall(args);
va_end(args);
}
Where this MagicalFunctionCall(args) would convert my args, for example:
1, "Test", 3.4, "OtherString"
into something like:
1 & "Test" & 3.4 & "OtherString"
I'm not necessarily tied to boost::preprocessor or anything boost really, but it would be ideal to accomplish this without pulling in any additional 3rd party dependencies (we already use boost elsewhere in the project). I just suggested those libraries, because they seemed to be the most promising in accomplishing all of the above.
Thanks!
Instead of Boost Format you could use the fmt library which supports older compilers ({fmt} 4 supports gcc 4.4):
void loggerFunc(const char *format, fmt::ArgList args) {
std::string s = fmt::format(format, args);
// log s
}
FMT_VARIADIC(void, loggerFunc, const char *)
The loggerFunc generated by FMT_VARIADIC can be used with variable number of arguments:
loggerFunc("{} {} {} {}", 1, "Test", 3.4, "OtherString");
Disclaimer: I'm the author of the fmt library.
Related
I just read about vectors in C++. They seem to be like lists in Python, but they can only take values of the datatype specified in the declaration. For example:
vector<int> intlist;
Takes only int type data. Whereas a list in Python take any type of data. I tried to implement the same in C++ by writing:
vector<auto> list;
But it resulted in an erroneous compilation. I am not sure why this happens as it works fine with other datatypes.
You're doing it the wrong way.
C++ is strong typed. auto is a keyword used when the type of variable can be determined at compile time, that's not what you want.
If you need to have a vector of object of different types, you must use some library like boost::any.
EDIT:
C++ is statically typed and Python dinamically typed, this is the difference. Thanks to #Angew for correcting my mistake.
auto is not a variant type, it is simply a shortcut you can use in your code when the type can be deduced by the compiler.
Underneath a Python list is some implementation of a variant and I would suggest using boost::python to manage C++ - Python interaction.
Also, if this is something you really want to achieve in c++ I recommend switching to c++17 and using std::variant. This is an example of using std::variant which at face-value may seem somewhat similar to a python array.
#include <variant>
#include <iostream>
#include <string>
using my_variant = std::variant<std::string, float, int, bool>;
int main(){
std::vector<my_variant> list = {"hello", 5.0, 10.0, "bye", false};
for(int i = 0; i < list.size(); i++){
std::visit([](auto arg){std::cout<<arg<<std::endl;}, list.at(i));
}
return 0;
}
I would like to give the users of my API the possibility to pass a custom format string.
Now, I know what kind of specifiers I am expecting (for a single double), and I would like to make clang aware of this.
The clang documentation (which actually just points to the gcc documentation) makes it seem as if I could only specify the format in terms of actual parameters to my function/method.
However, I would just like to tell clang: "If it contains one, and only one %f specifier (with whatever flags, width or precision the caller would like), it's OK"
I can't seem to find that information. Any pointers?
Thanks
Looking at the gcc documentation, I don't think there's a way to directly do what you want.
(I'm assuming that your goal is to require a format suitable for printing a single float.)
The closest thing I can think of, is if you have your function void myfunc(const char *fmt)
you could rewrite it as
extern void do_myfunc(const char *fmt); /* the real body of myfunc() */
inline void myfunc(const char *fmt) { /* put this in the header */
if (0) {
float f = 0.0f;
printf(fmt, f);
}
do_myfunc(fmt);
}
and rely on clang to remove the dead code. Of course, clang might complain about said dead code, then...
I have the following std::begin wrappers around Eigen3 matrices:
namespace std {
template<class T, int nd> auto begin(Eigen::Matrix<T,nd,1>& v)
-> decltype(v.data()) { return v.data(); }
}
Substitution fails, and I get a compiler error (error: no matching function for call to 'begin'). For this overload, clang outputs the following:
.../file:line:char note: candidate template ignored:
substitution failure [with T = double, nd = 4]
template<class T, int nd> auto begin(Eigen::Matrix<T,nd,1>& v)
^
I want this overload to be selected. I am expecting the types to be double and int, i.e. they are deduced as I want them to be deduced (and hopefully correctly). By looking at the function, I don't see anything that can actually fail.
Every now and then I get similar errors. Here, clang tells me: substitution failure, I'm not putting this function into the overload resolution set. However, this does not help me debugging at all. Why did substitution failed? What exactly couldn't be substituted where? The only thing obvious to me is that the compiler knows, but it is deliberately not telling me :(
Is it possible to force clang to tell me what did exactly fail here?
This function is trivial and I'm having problems. In more complex functions, I guess things can only get worse. How do you go about debugging these kind of errors?
You can debug substitution failures by doing the substitution yourself into a cut'n'paste of the original template and seeing what errors the compiler spews for the fully specialized code. In this case:
namespace std {
auto begin(Eigen::Matrix<double,4,1>& v)
-> decltype(v.data()) {
typedef double T; // Not necessary in this example,
const int nd = 4; // but define the parameters in general.
return v.data();
}
}
Well this has been reported as a bug in clang. Unfortunately, the clang devs still don't know the best way to fix it. Until then, you can use gcc which will report the backtrace, or you can apply this patch to clang 3.4. The patch is a quick hack that will turn substitution failures into errors.
I have a Swig-wrapped C library that I use in Ruby. I have no control over Swig or any interface definitions since that is done by the vendor of the interface.
No I find that there's a function in the library that has a char ** output parameter defined (among others). Example function definition:
void get_information(char * input, char **output, int someint)
Of course, my first attempt in Ruby was:
output_thing = ''
get_information "input", output_thing, 123
puts output_thing
This resulted in the error message
Expected argument 1 of type char **, but got String ""
Having no experience in Swig, I'm kindof stuck. Is it possible to make use of this function in Swig without defining or using a typemap?
Thanks in advance for your quick responses!
I found it (weee!)
There is a new_charpp method that creates the correct datatype. Apparently you have several of these methods for each of the primitives and commonly used datatypes (new_longpp, new_longlongpp, new_intpp et cetera).
Afterwards, you can read the correct contents from this variable using charpp_value(...)
apologies in advance if i use poor terminology.
when i compile a C++ app under gdb and use printf() it gives me awesome warnings relating to the consistency of the format string and the arguments passed in.
eg, this code:
printf("%s %s", "foo");
results in a compiler warning "too few arguments for format", which is super-useful.
it will also give warnings about format string type vs. argument type.
it must have inspected the format string and compared that against the supplied argument types.
- is this sort of compile-time introspection something which can be added to ordinary source code, or is it something which needs to be compiled into gcc itself ?
fwiw this is under gcc 4.2.1 on os x.
You can do stuff like this for your own printf-like functions (as well as for scanf/strftime/strfmon-like functions):
#define PRINTF_FORMAT_CHECK(format_index, args_index) __attribute__ ((__format__(printf, format_index, args_index)))
void my_printf(const char *fmt, ...) PRINTF_FORMAT_CHECK(1, 2);
See the gcc manual for further details.