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.

6
  • 1
    Incidentally, ... isn’t type safe, don’t use it; use C++11 variable template arguments instead. Commented Apr 29, 2013 at 16:15
  • @KonradRudolph: OP doesn't need variadic types, he needs variadic function args of the same type Commented Apr 29, 2013 at 16:23
  • @AndyT That’s irrelevant, the same solution applies since C++ doesn’t support same-type, type-safe variadic arguments. Commented Apr 29, 2013 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<int> v = {1, 2, 3}; do_something(v);. Commented Apr 29, 2013 at 17:31
  • @AndyT OP is using variadic arguments at the moment. Variadic templates do the same, just type safe. Commented Apr 29, 2013 at 17:53

2 Answers 2

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

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks for guiding me in the correct direction. That really helped a lot.
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.

2 Comments

sorry but I don't see how variadic templates are applicable here. OP uses variadic number of function args of the same type.
This really fixed my problem, even though I know it is not type safe. Thanks a lot for the fix.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.