[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());
    }@


  • Moderators

    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.



  • Yes, I want to use C++ variadic arguments or variadic templates, but I don't know how to modify a QString passed as argument.



  • you have to pass pointers to modify the passed arguments

    i recommend you to use QStringList it would be simpler
    and efficient

    you 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!



  • I try to avoid pointers, so I will use QStringList.



  • [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 ...


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.