2

I have been trying to figure out the problem that I am facing in the following piece of code.

#include <iostream>
#include <stdarg.h>
#include <vector>
using namespace std;

template <typename T>
class C {
        vector<T> vec;
    public:
        void PrintValues(int size, T val, ...){
            va_list v;
            va_start(v,val);
            for ( int i = 0 ; i < size ; i++ ) {
                T p = va_arg(v,T);
                vec.push_back(p);
                cout<<p<<" ";
            }
            va_end(v);
        }       
};

int main() {
    C<int> a;
    C<char *> b;
    cout<<endl;
    a.PrintValues(10,1,4,6,2,8,5,3,7,10,9);
    cout<<endl;
    b.PrintValues(10,"a","b","c","d","e","f","g","h","i","j");
    cout<<endl;
    return 0;
}

I compiled this code on my Ubuntu 10.04 desktop using g++ 4.4.3.

The code compiled with the following warning

testcode.cpp: In function ‘int main()’:
testcode.cpp:25: warning: deprecated conversion from string constant to ‘char*’

While I was expecting an output like

1 4 6 2 8 5 3 7 10 9
a b c d e f g h i j  

I actually got the following output

4 6 2 8 5 3 7 10 9 0
b c d e f g h i j `*@ 

Can someone please provide me with some pointers regarding why the first element in the list is skipped? I know that I can also do the same thing without using the variable argument list, but I am just trying out if this is possible.

Shafik Yaghmour
  • 154,301
  • 39
  • 440
  • 740
Gangs
  • 41
  • 1
  • 1
    Incidentally, `...` isn’t type safe, don’t use it; use C++11 variable template arguments instead. – Konrad Rudolph Apr 29 '13 at 16:15
  • @KonradRudolph: OP doesn't need variadic types, he needs variadic function args of the same type – Andriy Tylychko Apr 29 '13 at 16:23
  • @AndyT That’s irrelevant, the same solution applies since C++ doesn’t support same-type, type-safe variadic arguments. – Konrad Rudolph Apr 29 '13 at 17:21
  • @KonradRudolph: could you please elaborate? I really don't see how variadic templates can help here. It seems to me that OP tries to implement a convenient way to take arbitrary number of *the same type* args. Something that can be accomplished by initializer list, e.g. `vector v = {1, 2, 3}; do_something(v);`. – Andriy Tylychko Apr 29 '13 at 17:31
  • @AndyT OP is using variadic arguments at the moment. Variadic templates do the same, just type safe. – Konrad Rudolph Apr 29 '13 at 17:53
  • @KonradRudolph To be fair `std:::initializer_list` could possibly be a better solution since all the types are the same, which is what I added to my answer. BTW, this is also the recommendation here http://en.cppreference.com/w/cpp/utility/variadic as well. – Shafik Yaghmour Apr 30 '13 at 11:36

2 Answers2

2

Your first element is being put into the T val parameter, and not into va_list v;. This is because va_start(v, val) sets up v with the var-args which start after val, not including val. Have some documentation

Chowlett
  • 45,935
  • 20
  • 116
  • 150
1

You are eating the first part of your list in val argument and so you actually have one less element in your list than you are indicating with size:

 void PrintValues(int size, T val, ...)
                            ^^^^^

So in the first case val will be 1 and the second case a. One potential fix would be to drop the val arg:

void PrintValues(int size, ...)

and alter your va_start:

va_start(v,size);

I realize you are just experimenting but this is not type safe and we have variadic templates with C++11 now. Although since you are using only one type std:::initializer_list is also a viable alternative, as mentioned in the previous link.

Community
  • 1
  • 1
Shafik Yaghmour
  • 154,301
  • 39
  • 440
  • 740
  • sorry but I don't see how variadic templates are applicable here. OP uses variadic number of function args of the same type. – Andriy Tylychko Apr 29 '13 at 16:32
  • This really fixed my problem, even though I know it is not type safe. Thanks a lot for the fix. – Gangs Apr 29 '13 at 16:42