[SOLVED] Variable arguments
-
Hi.
I need a function that take a variable number of QStrings as arguments, and I need to change the value of some of them.func1(const QString & str1, QString & str2)
{
str2="a";
}
func2(const QString & str1, QString & str2, QString & str3)
{
str2="a";
str3="b";
}Thanks.
-
Use a non-const reference to a QStringList as argument ;-)
@func1(QStringList &strings)
{
//For example: modify string at index 42
strings[42] = "Hello world!";
}@The QStringList gives you maximum flexibility!
But if you want to work with individual strings, you could still make several overloads of your function under the same name.
@//Actual function with 3 args
func1(QString &str1, QString &str2, QString &str3)
{
//Do something with the strings
}//Wrapper for only 2 args
func1(QString &str1, QString &str2)
{
func1(str1, str2, QString());
}//Wrapper for only 1 arg
func1(QString &str1)
{
func1(str1, QString(), QString());
}@ -
you can also use "vargs C-feature":http://www.cprogramming.com/tutorial/lesson17.html.
Then you can avoid creating an extra QStringList and call the function with an abitrary count of arguments. But it's just a matter of flavor. -
you have to pass pointers to modify the passed arguments
i recommend you to use QStringList it would be simpler
and efficientyou can also avoid pointers, by returning the modified QStringList
@QStringList Function(const QStringList StringList)
{
QStringList TempStringList;// do required stuff
return TempStringList;
}@ -
[quote author="MarianMMX" date="1384164137"]Yes, I want to use C++ variadic arguments or variadic templates, but I don't know how to modify a QString passed as argument.[/quote]
You really should not be using variadic arguemnts in C++, because it's absolutely NOT type-safe! And there is NO way to determine the number of arguments, except by adding an extra argument that defines the number of arguments. Nowadays, in C++, we use overloaded functions instead!
But, if you insist, it can be done (only) like this:
@#include <stdarg.h>//The following variadic function will CRASH, if either
//1. The actual number of arguments is different from "count"
//2. The type of any of the arguments is not QString*
func1(const size_t count, ...)
{
va_list ap;
va_start(ap, count);//Iterate over all string for (size_t i = 0; i < count; i++) { QString *currentString = va_arg(ap, (QString*)); *currentString = "New string value"; } va_end(ap);
}
//Use like this
main()
{
QString a, b, c, d;func1(1, &a); func1(2, &a, &b); func1(3, &a, &b, &c); func1(4, &a, &b, &c, &d);
}
@Details:
http://www.cplusplus.com/reference/cstdarg/va_arg/[quote author="MarianMMX" date="1384164137"]but I don't know how to modify a QString passed as argument.[/quote]
See my previous post above!
-
[quote author="MarianMMX" date="1384174555"]I try to avoid pointers, so I will use QStringList.[/quote]
As in my example above, you can use references instead of pointers. Actually in your very first post you were using references, but you were using const references. Of course you can not modify a const reference. But you can modify a non-const reference, may it be a QString or a QStringList.
Also note: If you are passing a QString or QStringList by-value (i.e. not as a reference or pointer), your function will get a copy of the original QString or QStringList. Then you will be able to modify the copy, but you really only modify the copy, i.e. original QString or QStringList will not be modified.
@//Passing "by value", i.e. passing a COPY of the original
func1(QString str)
{
//Modifications to "str" will NOT be visible to caller!
}//Passing "by reference", i.e. passing a reference to the original
func1(QString &str)
{
//Modifications to "str" will be visible to caller!
}//Passing "by pointer", i.e. passing a pointer to the original
func1(QString *str)
{
//Modifications to "*str" will be visible to caller!
}@ -
bq. Of course you can not modify a const reference.
In the example in the first post only the first QString is const.
bq. As in my example above, you can use references instead of pointers.
So..
@for (size_t i = 0; i < count; i++){ QString currentString = va_arg(ap, (QString&)); currentString = "New string value"; }@
is OK?
-
You are not showing the signature of your function.
Nor are you calling va_start() and va_end() - or you are not showing that.
Anyway, I don't think passing references that way is possible.
If you really want the highly error-prone variadic version, use pointers:
@#include <stdarg.h>//WARNING: The following code will CRASH horribly, if the caller doesn't pass exactly "count" Pointers to QString's!
void func1(const size_t count, ...)
{
va_list ap;
va_start(ap, count);//Iterate over all string for (size_t i = 0; i < count; i++) { QString *currentString = va_arg(ap, QString*); *currentString = "New string value"; } va_end(ap);
}
int main()
{
QString a = "String #1";
QString b = "String #2";
func1(2, &a, &b);
}@Or just do it properly and safely:
@void func1(QStringList &strings)
{
for (size_t i = 0; i < strings.size(); i++)
{
strings[i] = "New string value";
}
}int main()
{
QStringList list;
list << "String #1" << "String #2";
func1(list);
}@ -
just for the record, a templated version would be:
@template<class... T> void f_template(T... args)
{
const int size = sizeof...(args);
QString *res[size] = {args...};
for(int i=0;i<size;i++)
{
*res[i] = "new string";
}
}
...
f_template(&s1,&s2,&s3,&s4);
...
@no need to pass the args count and is type safe ...
-
future users - stay away from va_args, they have always caused issues because people think they found a way to count the uncountable arguments (ie, depending on memory values, which differ depending on the compiler, not every compiler resets unused memory, if any, after the stored values and you may just be reading into undefined space causing at least an exception/crash or at worst catastrophic damage)
You can apply the above to class functions as well, even static ones and its important to note that template values with typenames specifiers will be deduced by the caller:
so calling "template<typename... T> func(T... args)" with func("a", "b") will turn that T into const char* automatically without having to specify func<const char*>Some people rejoining C++ after decades might think you would have to do that, and it is because of how explicit C++ used to be way back when (before ISO).
I've noticed this detail gets largely glossed over these days because the new C++ standard is largely implicit, but to oldschool programmers this is a detail you should probably be made aware of and that's C++'s many new "deductions" that have been signed into standard over the years. One such deduction is performed right before template expansion and that would be the above mentioned template type/classname deduction which is why you can call f_template(args) without doing f_template<type>(args).
-
You can refer to this code.
void my_printf(const char *format, ...) { va_list args; va_start(args, format); for (const char *p = format; *p != '\0'; p++) { if (*p == '%') { p++; // Move past '%' switch (*p) { case 'd': { // Handle integer int i = va_arg(args, int); printf("%d", i); break; } case 'c': { // Handle char char c = (char)va_arg(args, int); // char is promoted to int putchar(c); break; } case 's': { // Handle string char *s = va_arg(args, char *); printf("%s", s); break; } default: // Handle unknown format specifiers putchar('%'); putchar(*p); break; } } else { putchar(*p); // Print regular character } } va_end(args); }