views:

887

answers:

6

I can create an array initialized with elements like this:

int a[] = {10, 20, 30};

How do I create an STL vector and initialize it like the above? What is the best way to do so with the minimum typing effort?

The best I can do is:

std::vector<int> ints;

ints.push_back(10);
ints.push_back(20);
ints.push_back(30);

Though I could shorten it using macro magic... Other ideas?

+7  A: 

In C++0x you will be able to do it in the same way that you did with an array, but not in the current standard.

With only language support you can use:

int tmp[] = { 10, 20, 30 };
std::vector<int> v( tmp, tmp+3 ); // use some utility to avoid hardcoding the size here

If you can add other libraries you could try boost::assignment:

vector<int> v = list_of(10)(20)(30);

To avoid hardcoding the size of an array:

// option 1, typesafe, not a compile time constant
template <typename T, std::size_t N>
inline std::size_t size_of_array( T (&)[N] ) {
   return N;
}
// option 2, not typesafe, compile time constant
#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))

// option 3, typesafe, compile time constant
template <typename T, std::size_t N>
char (sizeof_array( T(&)[N] ))[N];    // declared, undefined
#define ARRAY_SIZE(x) sizeof(sizeof_array(x))
David Rodríguez - dribeas
I don't really care about the rep, but it would be nice knowing what part of the answer the downvoter considers to be wrong.
David Rodríguez - dribeas
Of course I didn't downvote but I have a question anyway: when is the size of an array not a compile time constant? I.e., in which cases would you use the first solution in your second snippet as opposed to the third one?
Manuel
+vote from my side. In C++0x you could make a `constexpr` of option 1. But then again, this won't be used anymore then :S
phresnel
@Manuel, the size of the array is part of the type, and as such it is a compile time constant. Now, option 1 uses that compile time constant 'N' as return value for a function. The return of a function is not a compile time, but runtime value, even if it will probably get inlined as the constant value at the place of call. The difference is that you cannot do: `int another[size_of_array(array)]`, while you can do `int another[ARRAY_SIZE(array)]`.
David Rodríguez - dribeas
@David - thanks for the good explanation, I see it now
Manuel
@Manuel: incomplete array types also exist, like `int[]`. I can put a declaration of such an array in a header and define it somewhere else (with completed type). Then, the size is not known during compilation of all other traslation units that just include the header. Array-to-pointer decay still works, sizeof does not.
sellibitze
+19  A: 

One method would be to use the array to initialize the vector

static const int arr[] = {16,2,77,29};
vector<int> vec (arr, arr + sizeof(arr) / sizeof(arr[0]) );
Yacoby
Please comment on downvotes. I provides the (IMHO) best example of a non library based solution. (Although Boost.Assign is a better idea if you can use Boost)
Yacoby
+1 - this is IMHO way preferrable over using boost for such a simple task.
Frerich Raabe
Ssssssssssmokin'!!
Vulcan Eager
Well I wouldn't add a Boost dependency only for this either.
Manuel
should be `static const int arr[] = ...`
sellibitze
@selibitze Thanks for pointing that out. Fixed.
Yacoby
Why static exactly? Why const even? Should work even without those. Right?
Vulcan Eager
@Agnel It will work fine without `static` or `const`, however they both make it more explicit as to how it should be used and allow the compiler to make additional optimizations.
Yacoby
+24  A: 

The Boost.Assign library uses non-macro magic to allow the following:

std::vector<int> v = boost::assign::list_of(1)(2)(3)(4);

Or, in two lines:

std::vector<int> v;
v += 1, 2, 3, 4;

But keep in mind that this has some overhead (basically, list_of constructs a std::deque under the hood) so for performance-critical code you'd be better off doing as Yacobi says.

Also, don't forget that what you are asking is not an issue if your compiler supports C++0x, as in that case you can simply do:

std::vector<int> v = {1, 2, 3, 4};

This is available in GCC as of version 4.4. Unfortunately, VC++ 2010 seems to be lagging behind in this respect.

Manuel
+3  A: 

you can do that using boost::assign.

vector<int> values;  
values += 1,2,3,4,5,6,7,8,9;

detail here

f4
A: 

If you want something on the same general order as Boost::assign without creating a dependency on Boost, the following is at least vaguely similar:

template<class T>
class make_vector {
    std::vector<T> data;
public:
    make_vector(T const &val) { 
        data.push_back(val);
    }

    make_vector<T> &operator,(T const &t) {
        data.push_back(t);
        return *this;
    }

    operator std::vector<T>() { return data; }
};

template<class T> 
make_vector<T> makeVect(T const &t) { 
    return make_vector<T>(t);
}

While I wish the syntax for using it was cleaner, it's still not particularly awful:

std::vector<int> x = (makeVect(1), 2, 3, 4);
Jerry Coffin
+1  A: 

If your compiler supports Variadic macros (which is true for most modern compilers), then you can use the following macro to turn vector initialization into a one-liner:

#define INIT_VECTOR(type, name, ...) \
static const type name##_a[] = __VA_ARGS__; \
vector<type> name(name##_a, name##_a + sizeof(name##_a) / sizeof(*name##_a))

With this macro, you can define an initialized vector with code like this:

INIT_VECTOR(int, my_vector, {1, 2, 3, 4});

This would create a new vector of ints named my_vector with the elements 1, 2, 3, 4.

Matt Ball