Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. [SOLVED] Variable arguments
Forum Updated to NodeBB v4.3 + New Features

[SOLVED] Variable arguments

Scheduled Pinned Locked Moved General and Desktop
13 Posts 7 Posters 13.0k Views 2 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • M Offline
    M Offline
    MuldeR
    wrote on last edited by
    #2

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

    My OpenSource software at: http://muldersoft.com/

    Qt v4.8.6 MSVC 2013, static/shared: http://goo.gl/BXqhrS

    Go visit the coop: http://youtu.be/Jay...

    1 Reply Last reply
    0
    • raven-worxR Offline
      raven-worxR Offline
      raven-worx
      Moderators
      wrote on last edited by
      #3

      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.

      --- SUPPORT REQUESTS VIA CHAT WILL BE IGNORED ---
      If you have a question please use the forum so others can benefit from the solution in the future

      1 Reply Last reply
      0
      • M Offline
        M Offline
        MarianMMX
        wrote on last edited by
        #4

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

        1 Reply Last reply
        0
        • K Offline
          K Offline
          kqt-mr-nv6
          wrote on last edited by
          #5

          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;
          }@

          1 Reply Last reply
          0
          • M Offline
            M Offline
            MuldeR
            wrote on last edited by
            #6

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

            My OpenSource software at: http://muldersoft.com/

            Qt v4.8.6 MSVC 2013, static/shared: http://goo.gl/BXqhrS

            Go visit the coop: http://youtu.be/Jay...

            1 Reply Last reply
            0
            • M Offline
              M Offline
              MarianMMX
              wrote on last edited by
              #7

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

              1 Reply Last reply
              0
              • M Offline
                M Offline
                MuldeR
                wrote on last edited by
                #8

                [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!
                }@

                My OpenSource software at: http://muldersoft.com/

                Qt v4.8.6 MSVC 2013, static/shared: http://goo.gl/BXqhrS

                Go visit the coop: http://youtu.be/Jay...

                1 Reply Last reply
                0
                • M Offline
                  M Offline
                  MarianMMX
                  wrote on last edited by
                  #9

                  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?

                  1 Reply Last reply
                  0
                  • M Offline
                    M Offline
                    MuldeR
                    wrote on last edited by
                    #10

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

                    My OpenSource software at: http://muldersoft.com/

                    Qt v4.8.6 MSVC 2013, static/shared: http://goo.gl/BXqhrS

                    Go visit the coop: http://youtu.be/Jay...

                    1 Reply Last reply
                    0
                    • N Offline
                      N Offline
                      NicuPopescu
                      wrote on last edited by
                      #11

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

                      1 Reply Last reply
                      2
                      • osirisgothraO Offline
                        osirisgothraO Offline
                        osirisgothra
                        wrote on last edited by
                        #12

                        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).

                        I'm truly glad you r/offmychess t finally, but please don't go too far, because you r/beyondvoxels and that implies that u r/donewithlife. Oh well time to git back to the lab, because azure sea here, I have a lot of work to do...

                        1 Reply Last reply
                        0
                        • crimson1023C Offline
                          crimson1023C Offline
                          crimson1023
                          wrote on last edited by
                          #13

                          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);
                          }
                          
                          1 Reply Last reply
                          0

                          • Login

                          • Login or register to search.
                          • First post
                            Last post
                          0
                          • Categories
                          • Recent
                          • Tags
                          • Popular
                          • Users
                          • Groups
                          • Search
                          • Get Qt Extensions
                          • Unsolved