3

i have tried to implement (kind of :) Initializer lists in older version of c++. like below..

#include <vector>
#include <cstdarg>
#include <iostream>

using namespace std;

template <class T>
vector <T> VEC_VA(size_t argCount,T arg1, ... )
{
    va_list arguments;
    vector <T> sList;

    va_start ( arguments, argCount);
    for ( int x = 0; x < (int)argCount; x++ )
        sList.push_back(va_arg ( arguments, T));
    va_end ( arguments );

    return sList;
}

struct Test
{
    Test(int _x,std::string _s):x(_x),s(_s){}
    int x;
    std::string s;
};

void methodWithArgs(vector<Test> testObjs)
{
    cout<<"Size:"<<testObjs.size()<<endl;
    for (std::vector<Test>::const_iterator it = testObjs.begin();it != testObjs.end();++it)
        std::cout << it->x <<":"<< it->s.c_str()<< std::endl;
}

int main()
{
    methodWithArgs(VEC_VA(2,Test(1,"one"),Test(2,"two")));
    return 0;
}

But this kind of implementation works in Visual studio 2012 (v11.0). But not in Linux g++ compiler. And ended with an Error: "cannot pass objects of non-trivially-copyable type ‘struct Test’ through ‘...’"

So is there any better idea?

Prasaathviki
  • 1,147
  • 2
  • 11
  • 22
  • 3
    You can checkout [boost assign](https://www.boost.org/doc/libs/1_44_0/libs/assign/doc/index.html). – Holt May 28 '19 at 11:16
  • Is `int x = 0;` a typo? Shouldn't it be `int x = 1;` since `arg1` is the first element? – L. F. May 28 '19 at 12:03
  • With gcc 6.3.0, I don't have your error message. However, to make it works, I made these modifications : no `T arg1` in the call, replace `count()` with `size()` and call the function with `VEC_VA` – Damien May 28 '19 at 13:54
  • Note that by using ellipsis you give up on type safety. There is no guarantee that arguments passed through ellipsis are instances of `T`. For example, in order to pass two floating point numbers one may be tempted to write `VEC_VA(2, 0.5, 1)`. Argument "0.5" is passed as `double`, so the result is a `vector` as expected. Argument "1" however is passed as `int`! Thus `va_arg(arguments, T)` (with `T = double`) is undefined in this case and your resulting vector will not look as expected. You would have to pass "1.0" insteand of "1" to fix that. This is very subtle and easy to overlook. – Daniel Junglas May 29 '19 at 07:44

2 Answers2

1

If you are willing to accept a slightly different syntax then all you need is a version of vector::push_back() that returns a reference to the vector. Something like this:

#include <vector>
#include <iostream>

template<typename T>
class VEC_VA_HELP {
   std::vector<T> vector;
public:
   VEC_VA_HELP(T arg1) : vector() { vector.push_back(arg1); }
   VEC_VA_HELP &operator()(T arg) { vector.push_back(arg); return *this; }
   operator std::vector<T> &() { return vector; }
};
template<typename T>
VEC_VA_HELP<T> VEC_VA(T arg1) { return VEC_VA_HELP<T>(arg1); }

struct Test {
   Test(int _x) : x(_x) {}
   int x;
};

void methodWithArgs(std::vector<Test> const &testObjs) {
   std::cout << testObjs.size() << std::endl;
   for (std::vector<Test>::const_iterator it = testObjs.begin();
        it != testObjs.end();
        ++it)
      std::cout << it->x << std::endl;
}

int
main(void)
{
   methodWithArgs(VEC_VA(Test(1))(Test(2))(Test(3)));
   return 0;
}

Also recursive templates come to mind but I am not sure how clean the syntax would be with them. See also this question about overloading the comma operator.

Daniel Junglas
  • 5,830
  • 1
  • 5
  • 22
0

Same as like this above answer by daniel But some improvements

template <class T>
class VECS
{
    vector <T> vec;
    public:
        VECS(){}
        VECS(T t){vec.push_back(t);}
        VECS& operator()(const T& t){vec.push_back(t);return *this;}
        typedef VECS<T> myVECS;
        myVECS& operator<< (const T& t){vec.push_back(t);return *this;}
        operator vector<T>() const {return vec;}
};

Usage

    methodWithArgs(VECS<Test>(Test(1,"one"))(Test(2,"two")));
    methodWithArgs(VECS<Test>()<<Test(1,"one")<<Test(2,"two"));
    methodWithArgs(VECS<Test>(Test(0,"zero")) <<Test(1,"one")<<Test(2,"two"));

    std::vector<int> v1 = VECS<int>() << 1 << 2 << 3;
    std::vector<int> v2 = VECS<int>(1)(2)(3);
Prasaathviki
  • 1,147
  • 2
  • 11
  • 22