In C++11, how would I go about writing a function (or method) that takes a std::array of known type but unknown size?
// made up example
void mulArray(std::array<int, ?>& arr, const int multiplier) {
for(auto& e : arr) {
e *= multiplier;
}
}
// lets imagine these being full of numbers
std::array<int, 17> arr1;
std::array<int, 6> arr2;
std::array<int, 95> arr3;
mulArray(arr1, 3);
mulArray(arr2, 5);
mulArray(arr3, 2);
During my search I only found suggestions to use templates, but those seems messy (method definitions in header) and excessive for what I'm trying to accomplish.
Is there a simple way to make this work, as one would with plain C-style arrays?
Is there a simple way to make this work, as one would with plain C-style arrays?
No. You really cannot do that unless you make your function a function template (or use another sort of container, like an std::vector, as suggested in the comments to the question):
template<std::size_t SIZE>
void mulArray(std::array<int, SIZE>& arr, const int multiplier) {
for(auto& e : arr) {
e *= multiplier;
}
}
Here is a live example.
The size of the array is part of the type, so you can't do quite what you want. There are a couple alternatives.
Preferred would be to take a pair of iterators:
template <typename Iter>
void mulArray(Iter first, Iter last, const int multiplier) {
for(; first != last; ++first) {
*first *= multiplier;
}
}
Alternately, use vector instead of array, which allows you to store the size at runtime rather than as part of its type:
void mulArray(std::vector<int>& arr, const int multiplier) {
for(auto& e : arr) {
e *= multiplier;
}
}
EDIT
C++20 tentatively includes std::span
https://en.cppreference.com/w/cpp/container/span
Original Answer
What you want is something like gsl::span, which is available in the Guideline Support Library described in the C++ Core Guidelines:
https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#SS-views
You can find an open-source header-only implementation of the GSL here:
https://github.com/Microsoft/GSL
With gsl::span, you can do this:
// made up example
void mulArray(gsl::span<int>& arr, const int multiplier) {
for(auto& e : arr) {
e *= multiplier;
}
}
// lets imagine these being full of numbers
std::array<int, 17> arr1;
std::array<int, 6> arr2;
std::array<int, 95> arr3;
mulArray(arr1, 3);
mulArray(arr2, 5);
mulArray(arr3, 2);
The problem with std::array is that its size is part of its type, so you'd have to use a template in order to implement a function that takes an std::array of arbitrary size.
gsl::span on the other hand stores its size as run-time information. This allows you to use one non-template function to accept an array of arbitrary size. It will also accept other contiguous containers:
std::vector<int> vec = {1, 2, 3, 4};
int carr[] = {5, 6, 7, 8};
mulArray(vec, 6);
mulArray(carr, 7);
Pretty cool, huh?
Absolutely, there is a simple way in C++11 to write a function that takes a std::array of known type, but unknown size.
If we are unable to pass the array size to the function, then instead, we can pass the memory address of where the array starts along with a 2nd address of where the array ends. Later, inside of the function, we can use these 2 memory addresses to calculate the size of the array!
#include <iostream>
#include <array>
// The function that can take a std::array of any size!
void mulArray(int* piStart, int* piLast, int multiplier){
// Calculate the size of the array (how many values it holds)
unsigned int uiArraySize = piLast - piStart;
// print each value held in the array
for (unsigned int uiCount = 0; uiCount < uiArraySize; uiCount++)
std::cout << *(piStart + uiCount) * multiplier << std::endl;
}
int main(){
// initialize an array that can can hold 5 values
std::array<int, 5> iValues{ 5, 10, 1, 2, 4 };
// Provide a pointer to both the beginning and end addresses of
// the array.
mulArray(iValues.begin(), iValues.end(), 2);
return 0;
}
Output at Console:
10, 20, 2, 4, 8
I tried below and it just worked for me.
#include <iostream>
#include <array>
using namespace std;
// made up example
void mulArray(auto &arr, const int multiplier)
{
for(auto& e : arr)
{
e *= multiplier;
}
}
void dispArray(auto &arr)
{
for(auto& e : arr)
{
std::cout << e << " ";
}
std::cout << endl;
}
int main()
{
// lets imagine these being full of numbers
std::array<int, 7> arr1 = {1, 2, 3, 4, 5, 6, 7};
std::array<int, 6> arr2 = {2, 4, 6, 8, 10, 12};
std::array<int, 9> arr3 = {1, 1, 1, 1, 1, 1, 1, 1, 1};
dispArray(arr1);
dispArray(arr2);
dispArray(arr3);
mulArray(arr1, 3);
mulArray(arr2, 5);
mulArray(arr3, 2);
dispArray(arr1);
dispArray(arr2);
dispArray(arr3);
return 0;
}
Output:
1 2 3 4 5 6 7
2 4 6 8 10 12
1 1 1 1 1 1 1 1 1
3 6 9 12 15 18 21
10 20 30 40 50 60
2 2 2 2 2 2 2 2 2
This can be done, but it takes a few steps to do cleanly. First, write a template class that represents a range of contiguous values. Then forward a template version that knows how big the array is to the Impl version that takes this contiguous range.
Finally, implement the contig_range version. Note that for( int& x: range ) works for contig_range, because I implemented begin() and end() and pointers are iterators.
template<typename T>
struct contig_range {
T* _begin, _end;
contig_range( T* b, T* e ):_begin(b), _end(e) {}
T const* begin() const { return _begin; }
T const* end() const { return _end; }
T* begin() { return _begin; }
T* end() { return _end; }
contig_range( contig_range const& ) = default;
contig_range( contig_range && ) = default;
contig_range():_begin(nullptr), _end(nullptr) {}
// maybe block `operator=`? contig_range follows reference semantics
// and there really isn't a run time safe `operator=` for reference semantics on
// a range when the RHS is of unknown width...
// I guess I could make it follow pointer semantics and rebase? Dunno
// this being tricky, I am tempted to =delete operator=
template<typename T, std::size_t N>
contig_range( std::array<T, N>& arr ): _begin(&*std::begin(arr)), _end(&*std::end(arr)) {}
template<typename T, std::size_t N>
contig_range( T(&arr)[N] ): _begin(&*std::begin(arr)), _end(&*std::end(arr)) {}
template<typename T, typename A>
contig_range( std::vector<T, A>& arr ): _begin(&*std::begin(arr)), _end(&*std::end(arr)) {}
};
void mulArrayImpl( contig_range<int> arr, const int multiplier );
template<std::size_t N>
void mulArray( std::array<int, N>& arr, const int multiplier ) {
mulArrayImpl( contig_range<int>(arr), multiplier );
}
(not tested, but design should work).
Then, in your .cpp file:
void mulArrayImpl(contig_range<int> rng, const int multiplier) {
for(auto& e : rng) {
e *= multiplier;
}
}
This has the downside that the code that loops over the contents of the array doesn't know (at compile time) how big the array is, which could cost optimization. It has the advantage that the implementation doesn't have to be in the header.
Be careful about explicitly constructing a contig_range, as if you pass it a set it will assume that the set data is contiguous, which is false, and do undefined behavior all over the place. The only two std containers that this is guaranteed to work on are vector and array (and C-style arrays, as it happens!). deque despite being random access isn't contiguous (dangerously, it is contiguous in small chunks!), list is not even close, and the associative (ordered and unordered) containers are equally non-contiguous.
So the three constructors I implemented where std::array, std::vector and C-style arrays, which basically covers the bases.
Implementing [] is easy as well, and between for() and [] that is most of what you want an array for, isn't it?
Related
I have project where I am working with both fixed and variable length arrays of bytes. I want to have a function that can concatenate two arbitrary containers of bytes and return a single vector. Currently I am using
std::vector<uint8_t> catBytes(uint8_t const* bytes1, size_t const len1,
uint8_t const* bytes2, size_t const len2) {
std::vector<uint8_t> all_bytes;
all_bytes.reserve(len1 + len2);
all_bytes.insert(all_bytes.begin(), bytes1, bytes1 + len1);
all_bytes.insert(all_bytes.begin() + len1, bytes2, bytes2 + len2);
return all_bytes;
} // catBytes
However, I would like more generic way to do this, which better uses the capabilities of C++. I do not want to just accept iterators. I am trying to figure out how to accept two arbitrary containers and return a vector containing their contents. Ideally I would also not like to have to know the type inside the vector.
Something like
std::vector<unit_8> v1 = { 1, 2, 3, 4 };
std::array<unit_8, 4> a1 = { 1, 2, 3, 4 };
std::array<unit_8, 2> a2 = { 1, 2 };
auto res1 = concat(v1, a1); // std::vector<uint_8> of size 8
auto res2 = concat(a1, a2); // std::vector<uint_8> of size 6
// or
std::vector<char> v2 = { 1, 2, 3, 4 };
std::array<char, 4> a3 = { 1, 2, 3, 4 };
auto res3 = concat(v1, a1); // std::vector<char> of size 8
I think there is a templated approach to this but I just have not been able to figure it out.
std::array, std::vector and other contiguous_ranges can be converted to a lightweight std::span, which you can use for type erasure.
#include <cstdint>
#include <span>
#include <vector>
std::vector<uint8_t>
catBytes(std::span<const uint8_t> x, std::span<const uint8_t> y) {
std::vector<uint8_t> all_bytes;
all_bytes.reserve(x.size() + y.size());
all_bytes.insert(all_bytes.begin(), x.begin(), x.end());
all_bytes.insert(all_bytes.end(), y.begin(), y.end());
return all_bytes;
}
Demo
In general, generic + arbitrary, means templates.
Something like this?
template<class SizedRange1, class SizedRange2>
auto concat(SizedRange1 const& r1, SizedRange2 const& r2) {
std::vector<typename SizedRange1::value_type> ret;
ret.reserve(r1.size() + r2.size());
using std::begin; using std::end;
ret.insert(ret.end(), begin(r1), end(r1));
ret.insert(ret.end(), begin(r2), end(r2));
return ret;
}
EDIT:
The advantage of #康桓瑋's solution (which assumes that you are only interested in concatenating contiguous memory containers as you stated) is that you have a single function and you avoid code bloat.
As you noticed in the comments, the problem with that you can not deduce the element type, which can be anything in principle, so you are back to needing templates anyway.
Fortunately, you can combine the two approaches and reduce the number of functions generated as machine code, in the case that you have many different input containers, which is combinatorial.
template<class T>
std::vector<T>
concat_aux(std::span<const T> x, std::span<const T> y) {
std::vector<T> ret;
ret.reserve(x.size() + y.size());
ret.insert(ret.end(), x.begin(), x.end());
ret.insert(ret.end(), y.begin(), y.end());
return ret;
}
template<class ContinuousRange1, class ContinuousRange2>
auto concat(ContinuousRange1 const& r1, ContinuousRange2 const& r2) {
return concat_aux<typename ContinousRange1::value_type>(r1, r2);
}
The advantage is marginal here, but if the function concat is very complicated this last approach will pay off because it will generate code only for the different types of elements, not the number of containers squared in your instantiating code.
Assuming I have following vector of vectors with the same size:
std::vector<float> a({1, 1, 1});
std::vector<float> b({2, 2, 2});
std::vector<float> c({4, 4, 5});
I would like to get the element-wise mean vector:
std::vector<float> mean({2.333, 2.333, 2.666});
What's the most elegant way to achieve this?
I can write for-loops to do so but was wondering is there better way to do so.
Also note that I would like the solution to scale to any number of vectors (I'm using three vectors for the sake of giving examples)
For element-wise operations, you should be using std::valarray. Primer:
std::valarray<float> a { 1, 1, 1 };
std::valarray<float> b { 2, 2, 2 };
std::valarray<float> c { 4, 4, 5 };
std::valarray<float> mean = (a + b + c) / 3.f;
std::vector<float> v{std::begin(mean), std::end(mean)}
This works in C++11 mode with GCC 7.2.1. Now you haven't specified how you're feeding in the vectors, so what you want isn't clear. If you know in advance how many vectors you'll be dealing with, this should work:
std::valarray<float> foo(std::vector<std::valarray<float>> args) {
assert(args.size() > 0);
// sum MUST be initialized with a size
// and in this case, all sizes must be the same
// otherwise += is undefined behavior
std::valarray<float> sum(args[0].size());
for (auto c : args) {
sum += c;
}
return (sum / (float)args.size());
}
If your inner vectors have always the same size, std::vector seems not like a good choice (it creates unnecessary many small heap allocations and decreases data locality). Better use std::array, or define your own class Vec:
#include <vector>
#include <array>
#include <numeric>
#include <algorithm>
template <typename T, std::size_t N>
struct Vec : std::array<T, N> {
Vec() = default;
explicit Vec(std::array<T, N> const& a): std::array<T, N>(a) {}
static Vec zero() { return Vec(std::array<T, N>{0}); }
Vec operator + (Vec const& rhs) const {
Vec result;
std::transform(std::begin(*this), std::end(*this), std::begin(rhs), std::begin(result), std::plus<T>());
return result;
}
template <typename T2>
Vec operator / (T2 const& rhs) const {
Vec result;
std::transform(std::begin(*this), std::end(*this), std::begin(result), [&](T const& lhs) { return lhs/rhs; });
return result;
}
};
Vec<float, 3> elementwise_mean(std::vector<Vec<float, 3>> vecvec) {
return std::accumulate(std::begin(vecvec), std::end(vecvec), Vec<float, 3>::zero()) / vecvec.size();
}
Or you can be lazy and use a dedicated library like eigen3.
What is the "most elegant way" to achive OP's goal is a matter of opinion, I'm afraid, but surely we can replace most of the explicit for loops with algorithms from the Standard Library.
A vector of vectors may not be the best data structure for every use case and moreover, traversing this object column-wise may not be very cache friendly. However, even if it's mandatory, we can still perform all the needed calculation by traversing the container row-wise, accumulating the sums of each column in a temporary vector and finally computing the averages.
This snippet shows a possible (slightly more general) implementation:
#include <iostream>
#include <vector>
#include <array>
#include <iterator>
#include <stdexcept>
#include <algorithm>
#include <functional>
template<class ReturnType = double, class Container>
auto elementwise_mean(Container const& mat)
{
using MeansType = std::vector<ReturnType>;
using DistType = typename MeansType::iterator::difference_type;
auto it_row = std::begin(mat);
auto n_rows = std::distance(it_row, std::end(mat));
if ( n_rows == 0 )
throw std::runtime_error("The container is empty");
MeansType means(std::begin(*it_row), std::end(*it_row));
const DistType row_size = means.size();
if ( row_size == 0 )
throw std::runtime_error("The first row is empty");
std::for_each(
++it_row, std::end(mat),
[&means, row_size](auto const& row) {
if ( row_size != std::distance(std::begin(row), std::end(row)) )
throw std::runtime_error("A row has a wrong length");
std::transform(
means.begin(), means.end(), std::begin(row),
means.begin(), std::plus()
);
}
);
std::for_each(means.begin(), means.end(), [n_rows](auto & a){ a /= n_rows; });
return means;
}
template<class Container> void print_out(Container const& c);
int main()
{
std::vector<std::vector<double>> test {
{1.0, 1.0, 1.0},
{2.0, 2.0, 2.0},
{4.0, 4.0, 5.0}
};
auto means = elementwise_mean(test);
print_out(means); // --> 2.33333 2.33333 2.66667
std::array<int, 4> test2[2] = {
{{1, 3, -5, 6}},
{{2, 5, 6, -8}},
};
auto means2 = elementwise_mean<float>(test2);
print_out(means2); // --> 1.5 4 0.5 -1
auto means3 = elementwise_mean<int>(test2);
print_out(means3); // --> 1 4 0 -1
}
template<class Container>
void print_out(Container const& c)
{
for ( const auto x : c )
std::cout << ' ' << x;
std::cout << '\n';
}
I'm trying to figure this out, and, it's really annoying me. I have a function that converts either an array or a vector into a vector of complex numbers, but, I do not know how it would be possible for the function to be able to accept both double arrays, as well as double vectors. I've tried using templates, but, this does not seem to work.template
template<typename T>
vector<Complex::complex> convertToComplex(T &vals)
{
}
Value::Value(vector<double> &vals, int N) {
};
Value::Value(double *vals, int N) {
};
What I am hoping for is this:
int main()
{
double[] vals = {1, 2, 3, 4, 5};
int foo = 4;
Value v(vals, foo); // this would work and pass the array to the constructor, which would
// then pass the values to the function and covert this to a
// vector<complex>
}
I could do the same for a vector as well.. I don't know whether or not templates are the right approach for this.
You could make your function and constructor a template that takes two iterators:
template<typename Iterator>
vector<Complex::complex> convertToComplex(Iterator begin, Iterator end)
{
}
class Value
{
public:
template <Iteraror>
Value(Iterator begin, Iterator end)
{
vector<Complex::complex> vec = comvertToComplex(begin, end);
}
....
};
then
double[] vals = {1, 2, 3, 4, 5};
Value v(std::begin(vals), std::end(vals));
std::vector<double> vec{1,2,3,4,5,6,7};
Value v2(v.begin(), v.end());
I have omitted foo because it isn't very clear to me what its role is.
No need to define a template function here if you only want to support doubles.
You should do it like this, it's much simpler:
vector<Complex::complex> convertToComplex(const double* array, size_t len)
{
// ... your implementation
}
vector<Complex::complex> convertToComplex(const vector<double>& v, size_t len)
{
return convertToComplex(v.data(), len);
}
That's it!
In C++11, how would I go about writing a function (or method) that takes a std::array of known type but unknown size?
// made up example
void mulArray(std::array<int, ?>& arr, const int multiplier) {
for(auto& e : arr) {
e *= multiplier;
}
}
// lets imagine these being full of numbers
std::array<int, 17> arr1;
std::array<int, 6> arr2;
std::array<int, 95> arr3;
mulArray(arr1, 3);
mulArray(arr2, 5);
mulArray(arr3, 2);
During my search I only found suggestions to use templates, but those seems messy (method definitions in header) and excessive for what I'm trying to accomplish.
Is there a simple way to make this work, as one would with plain C-style arrays?
Is there a simple way to make this work, as one would with plain C-style arrays?
No. You really cannot do that unless you make your function a function template (or use another sort of container, like an std::vector, as suggested in the comments to the question):
template<std::size_t SIZE>
void mulArray(std::array<int, SIZE>& arr, const int multiplier) {
for(auto& e : arr) {
e *= multiplier;
}
}
Here is a live example.
The size of the array is part of the type, so you can't do quite what you want. There are a couple alternatives.
Preferred would be to take a pair of iterators:
template <typename Iter>
void mulArray(Iter first, Iter last, const int multiplier) {
for(; first != last; ++first) {
*first *= multiplier;
}
}
Alternately, use vector instead of array, which allows you to store the size at runtime rather than as part of its type:
void mulArray(std::vector<int>& arr, const int multiplier) {
for(auto& e : arr) {
e *= multiplier;
}
}
EDIT
C++20 tentatively includes std::span
https://en.cppreference.com/w/cpp/container/span
Original Answer
What you want is something like gsl::span, which is available in the Guideline Support Library described in the C++ Core Guidelines:
https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#SS-views
You can find an open-source header-only implementation of the GSL here:
https://github.com/Microsoft/GSL
With gsl::span, you can do this:
// made up example
void mulArray(gsl::span<int>& arr, const int multiplier) {
for(auto& e : arr) {
e *= multiplier;
}
}
// lets imagine these being full of numbers
std::array<int, 17> arr1;
std::array<int, 6> arr2;
std::array<int, 95> arr3;
mulArray(arr1, 3);
mulArray(arr2, 5);
mulArray(arr3, 2);
The problem with std::array is that its size is part of its type, so you'd have to use a template in order to implement a function that takes an std::array of arbitrary size.
gsl::span on the other hand stores its size as run-time information. This allows you to use one non-template function to accept an array of arbitrary size. It will also accept other contiguous containers:
std::vector<int> vec = {1, 2, 3, 4};
int carr[] = {5, 6, 7, 8};
mulArray(vec, 6);
mulArray(carr, 7);
Pretty cool, huh?
Absolutely, there is a simple way in C++11 to write a function that takes a std::array of known type, but unknown size.
If we are unable to pass the array size to the function, then instead, we can pass the memory address of where the array starts along with a 2nd address of where the array ends. Later, inside of the function, we can use these 2 memory addresses to calculate the size of the array!
#include <iostream>
#include <array>
// The function that can take a std::array of any size!
void mulArray(int* piStart, int* piLast, int multiplier){
// Calculate the size of the array (how many values it holds)
unsigned int uiArraySize = piLast - piStart;
// print each value held in the array
for (unsigned int uiCount = 0; uiCount < uiArraySize; uiCount++)
std::cout << *(piStart + uiCount) * multiplier << std::endl;
}
int main(){
// initialize an array that can can hold 5 values
std::array<int, 5> iValues{ 5, 10, 1, 2, 4 };
// Provide a pointer to both the beginning and end addresses of
// the array.
mulArray(iValues.begin(), iValues.end(), 2);
return 0;
}
Output at Console:
10, 20, 2, 4, 8
I tried below and it just worked for me.
#include <iostream>
#include <array>
using namespace std;
// made up example
void mulArray(auto &arr, const int multiplier)
{
for(auto& e : arr)
{
e *= multiplier;
}
}
void dispArray(auto &arr)
{
for(auto& e : arr)
{
std::cout << e << " ";
}
std::cout << endl;
}
int main()
{
// lets imagine these being full of numbers
std::array<int, 7> arr1 = {1, 2, 3, 4, 5, 6, 7};
std::array<int, 6> arr2 = {2, 4, 6, 8, 10, 12};
std::array<int, 9> arr3 = {1, 1, 1, 1, 1, 1, 1, 1, 1};
dispArray(arr1);
dispArray(arr2);
dispArray(arr3);
mulArray(arr1, 3);
mulArray(arr2, 5);
mulArray(arr3, 2);
dispArray(arr1);
dispArray(arr2);
dispArray(arr3);
return 0;
}
Output:
1 2 3 4 5 6 7
2 4 6 8 10 12
1 1 1 1 1 1 1 1 1
3 6 9 12 15 18 21
10 20 30 40 50 60
2 2 2 2 2 2 2 2 2
This can be done, but it takes a few steps to do cleanly. First, write a template class that represents a range of contiguous values. Then forward a template version that knows how big the array is to the Impl version that takes this contiguous range.
Finally, implement the contig_range version. Note that for( int& x: range ) works for contig_range, because I implemented begin() and end() and pointers are iterators.
template<typename T>
struct contig_range {
T* _begin, _end;
contig_range( T* b, T* e ):_begin(b), _end(e) {}
T const* begin() const { return _begin; }
T const* end() const { return _end; }
T* begin() { return _begin; }
T* end() { return _end; }
contig_range( contig_range const& ) = default;
contig_range( contig_range && ) = default;
contig_range():_begin(nullptr), _end(nullptr) {}
// maybe block `operator=`? contig_range follows reference semantics
// and there really isn't a run time safe `operator=` for reference semantics on
// a range when the RHS is of unknown width...
// I guess I could make it follow pointer semantics and rebase? Dunno
// this being tricky, I am tempted to =delete operator=
template<typename T, std::size_t N>
contig_range( std::array<T, N>& arr ): _begin(&*std::begin(arr)), _end(&*std::end(arr)) {}
template<typename T, std::size_t N>
contig_range( T(&arr)[N] ): _begin(&*std::begin(arr)), _end(&*std::end(arr)) {}
template<typename T, typename A>
contig_range( std::vector<T, A>& arr ): _begin(&*std::begin(arr)), _end(&*std::end(arr)) {}
};
void mulArrayImpl( contig_range<int> arr, const int multiplier );
template<std::size_t N>
void mulArray( std::array<int, N>& arr, const int multiplier ) {
mulArrayImpl( contig_range<int>(arr), multiplier );
}
(not tested, but design should work).
Then, in your .cpp file:
void mulArrayImpl(contig_range<int> rng, const int multiplier) {
for(auto& e : rng) {
e *= multiplier;
}
}
This has the downside that the code that loops over the contents of the array doesn't know (at compile time) how big the array is, which could cost optimization. It has the advantage that the implementation doesn't have to be in the header.
Be careful about explicitly constructing a contig_range, as if you pass it a set it will assume that the set data is contiguous, which is false, and do undefined behavior all over the place. The only two std containers that this is guaranteed to work on are vector and array (and C-style arrays, as it happens!). deque despite being random access isn't contiguous (dangerously, it is contiguous in small chunks!), list is not even close, and the associative (ordered and unordered) containers are equally non-contiguous.
So the three constructors I implemented where std::array, std::vector and C-style arrays, which basically covers the bases.
Implementing [] is easy as well, and between for() and [] that is most of what you want an array for, isn't it?
I can create an array and initialize it like this:
int a[] = {10, 20, 30};
How do I create a std::vector and initialize it similarly elegant?
The best way I know is:
std::vector<int> ints;
ints.push_back(10);
ints.push_back(20);
ints.push_back(30);
Is there a better way?
If your compiler supports C++11, 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.
Alternatively, the Boost.Assign library uses non-macro magic to allow the following:
#include <boost/assign/list_of.hpp>
...
std::vector<int> v = boost::assign::list_of(1)(2)(3)(4);
Or:
#include <boost/assign/std/vector.hpp>
using namespace boost::assign;
...
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 Yacoby says.
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]) );
If you can, use the modern C++[11,14,17,20,...] way:
std::vector<int> ints = {10, 20, 30};
The old way of looping over a variable-length array or using sizeof() is truly terrible on the eyes and completely unnecessary in terms of mental overhead. Yuck.
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))
In C++11:
#include <vector>
using std::vector;
...
vector<int> vec1 { 10, 20, 30 };
// or
vector<int> vec2 = { 10, 20, 30 };
Using Boost list_of:
#include <vector>
#include <boost/assign/list_of.hpp>
using std::vector;
...
vector<int> vec = boost::assign::list_of(10)(20)(30);
Using Boost assign:
#include <vector>
#include <boost/assign/std/vector.hpp>
using std::vector;
...
vector<int> vec;
vec += 10, 20, 30;
Conventional STL:
#include <vector>
using std::vector;
...
static const int arr[] = {10,20,30};
vector<int> vec (arr, arr + sizeof(arr) / sizeof(arr[0]) );
Conventional STL with generic macros:
#include <vector>
#define ARRAY_SIZE(ar) (sizeof(ar) / sizeof(ar[0])
#define ARRAY_END(ar) (ar + ARRAY_SIZE(ar))
using std::vector;
...
static const int arr[] = {10,20,30};
vector<int> vec (arr, ARRAY_END(arr));
Conventional STL with a vector initializer macro:
#include <vector>
#define INIT_FROM_ARRAY(ar) (ar, ar + sizeof(ar) / sizeof(ar[0])
using std::vector;
...
static const int arr[] = {10,20,30};
vector<int> vec INIT_FROM_ARRAY(arr);
I tend to declare
template< typename T, size_t N >
std::vector<T> makeVector( const T (&data)[N] )
{
return std::vector<T>(data, data+N);
}
in a utility header somewhere and then all that's required is:
const double values[] = { 2.0, 1.0, 42.0, -7 };
std::vector<double> array = makeVector(values);
Before C++ 11:
Method 1
vector<int> v(arr, arr + sizeof(arr)/sizeof(arr[0]));
Method 2
vector<int>v;
v.push_back(SomeValue);
C++ 11 onward below is also possible
vector<int>v = {1, 3, 5, 7};
We can do this as well
vector<int>v {1, 3, 5, 7}; // Notice .. no "=" sign
For C++ 17 onwards we can omit the type
vector v = {1, 3, 5, 7};
Starting with:
int a[] = {10, 20, 30}; //I'm assuming 'a' is just a placeholder
If you don't have a C++11 compiler and you don't want to use Boost:
const int a[] = {10, 20, 30};
const std::vector<int> ints(a, a+sizeof(a)/sizeof(int)); //Make it const if you can
If you don't have a C++11 compiler and can use Boost:
#include <boost/assign.hpp>
const std::vector<int> ints = boost::assign::list_of(10)(20)(30);
If you do have a C++11 compiler:
const std::vector<int> ints = {10,20,30};
For vector initialisation -
vector<int> v = {10, 20, 30}
can be done if you have a C++11 compiler.
Else, you can have an array of the data and then use a for loop.
int array[] = {10,20,30}
for(unsigned int i=0; i<sizeof(array)/sizeof(array[0]); i++)
{
v.push_back(array[i]);
}
Apart from these, there are various other ways described in previous answers using some code. In my opinion, these ways are easy to remember and quick to write.
The easiest way to do it is:
vector<int> ints = {10, 20, 30};
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.
I build my own solution using va_arg. This solution is C++98 compliant.
#include <cstdarg>
#include <iostream>
#include <vector>
template <typename T>
std::vector<T> initVector (int len, ...)
{
std::vector<T> v;
va_list vl;
va_start(vl, len);
for (int i = 0; i < len; ++i)
v.push_back(va_arg(vl, T));
va_end(vl);
return v;
}
int main ()
{
std::vector<int> v = initVector<int> (7,702,422,631,834,892,104,772);
for (std::vector<int>::const_iterator it = v.begin() ; it != v.end(); ++it)
std::cout << *it << std::endl;
return 0;
}
Demo
If you don't want to use Boost, but want to enjoy syntax like
std::vector<int> v;
v+=1,2,3,4,5;
just include this chunk of code
template <class T> class vector_inserter{
public:
std::vector<T>& v;
vector_inserter(std::vector<T>& v):v(v){}
vector_inserter& operator,(const T& val){v.push_back(val);return *this;}
};
template <class T> vector_inserter<T> operator+=(std::vector<T>& v,const T& x){
return vector_inserter<T>(v),x;
}
In C++11:
static const int a[] = {10, 20, 30};
vector<int> vec (begin(a), end(a));
A more recent duplicate question has this answer by Viktor Sehr. For me, it is compact, visually appealing (looks like you are 'shoving' the values in), doesn't require C++11 or a third-party module, and avoids using an extra (written) variable. Below is how I am using it with a few changes. I may switch to extending the function of vector and/or va_arg in the future instead.
// Based on answer by "Viktor Sehr" on Stack Overflow
// https://stackoverflow.com/a/8907356
//
template <typename T>
class mkvec {
public:
typedef mkvec<T> my_type;
my_type& operator<< (const T& val) {
data_.push_back(val);
return *this;
}
my_type& operator<< (const std::vector<T>& inVector) {
this->data_.reserve(this->data_.size() + inVector.size());
this->data_.insert(this->data_.end(), inVector.begin(), inVector.end());
return *this;
}
operator std::vector<T>() const {
return data_;
}
private:
std::vector<T> data_;
};
std::vector<int32_t> vec1;
std::vector<int32_t> vec2;
vec1 = mkvec<int32_t>() << 5 << 8 << 19 << 79;
// vec1 = (5, 8, 19, 79)
vec2 = mkvec<int32_t>() << 1 << 2 << 3 << vec1 << 10 << 11 << 12;
// vec2 = (1, 2, 3, 5, 8, 19, 79, 10, 11, 12)
You can do that using boost::assign:
vector<int> values;
values += 1,2,3,4,5,6,7,8,9;
Details are here.
The below methods can be used to initialize the vector in C++.
int arr[] = {1, 3, 5, 6}; vector<int> v(arr, arr + sizeof(arr)/sizeof(arr[0]));
vector<int>v; v.push_back(1); v.push_back(2); v.push_back(3); and so on
vector<int>v = {1, 3, 5, 7};
The third one is allowed only in C++11 onwards.
There are a lot of good answers here, but since I independently arrived at my own before reading this, I figured I'd toss mine up here anyway...
Here's a method that I'm using for this which will work universally across compilers and platforms:
Create a struct or class as a container for your collection of objects. Define an operator overload function for <<.
class MyObject;
struct MyObjectList
{
std::list<MyObject> objects;
MyObjectList& operator<<( const MyObject o )
{
objects.push_back( o );
return *this;
}
};
You can create functions which take your struct as a parameter, e.g.:
someFunc( MyObjectList &objects );
Then, you can call that function, like this:
someFunc( MyObjectList() << MyObject(1) << MyObject(2) << MyObject(3) );
That way, you can build and pass a dynamically sized collection of objects to a function in one single clean line!
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);
typedef std::vector<int> arr;
arr a {10, 20, 30}; // This would be how you initialize while defining
To compile use:
clang++ -std=c++11 -stdlib=libc++ <filename.cpp>
// Before C++11
// I used following methods:
// 1.
int A[] = {10, 20, 30}; // original array A
unsigned sizeOfA = sizeof(A)/sizeof(A[0]); // calculate the number of elements
// declare vector vArrayA,
std::vector<int> vArrayA(sizeOfA); // make room for all
// array A integers
// and initialize them to 0
for(unsigned i=0; i<sizeOfA; i++)
vArrayA[i] = A[i]; // initialize vector vArrayA
//2.
int B[] = {40, 50, 60, 70}; // original array B
std::vector<int> vArrayB; // declare vector vArrayB
for (unsigned i=0; i<sizeof(B)/sizeof(B[0]); i++)
vArrayB.push_back(B[i]); // initialize vArrayB
//3.
int C[] = {1, 2, 3, 4}; // original array C
std::vector<int> vArrayC; // create an empty vector vArrayC
vArrayC.resize(sizeof(C)/sizeof(C[0])); // enlarging the number of
// contained elements
for (unsigned i=0; i<sizeof(C)/sizeof(C[0]); i++)
vArrayC.at(i) = C[i]; // initialize vArrayC
// A Note:
// Above methods will work well for complex arrays
// with structures as its elements.
It is pretty convenient to create a vector inline without defining variable when writing test, for example:
assert(MyFunction() == std::vector<int>{1, 3, 4}); // <- this.
"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 easiest way to initialize a vector as you've initialized your built-in array is using an initializer list which was introduced in C++11.
// Initializing a vector that holds 2 elements of type int.
Initializing:
std::vector<int> ivec = {10, 20};
// The push_back function is more of a form of assignment with the exception of course
//that it doesn't obliterate the value of the object it's being called on.
Assigning
ivec.push_back(30);
ivec is 3 elements in size after Assigning (labeled statement) is executed.
There are various ways to hardcode a vector. I will share few ways:
Initializing by pushing values one by one
// Create an empty vector
vector<int> vect;
vect.push_back(10);
vect.push_back(20);
vect.push_back(30);
Initializing like arrays
vector<int> vect{ 10, 20, 30 };
Initializing from an array
int arr[] = { 10, 20, 30 };
int n = sizeof(arr) / sizeof(arr[0]);
vector<int> vect(arr, arr + n);
Initializing from another vector
vector<int> vect1{ 10, 20, 30 };
vector<int> vect2(vect1.begin(), vect1.end());
If the array is:
int arr[] = {1, 2, 3};
int len = (sizeof(arr)/sizeof(arr[0])); // finding length of array
vector < int > v;
v.assign(arr, arr+len); // assigning elements from array to vector
Related, you can use the following if you want to have a vector completely ready to go in a quick statement (e.g. immediately passing to another function):
#define VECTOR(first,...) \
([](){ \
static const decltype(first) arr[] = { first,__VA_ARGS__ }; \
std::vector<decltype(first)> ret(arr, arr + sizeof(arr) / sizeof(*arr)); \
return ret;})()
example function
template<typename T>
void test(std::vector<T>& values)
{
for(T value : values)
std::cout<<value<<std::endl;
}
example use
test(VECTOR(1.2f,2,3,4,5,6));
though be careful about the decltype, make sure the first value is clearly what you want.
B. Stroustrup describes a nice way to chain operations in 16.2.10 Selfreference on page 464 in the C++11 edition of the Prog. Lang. where a function returns a reference, here modified to a vector. This way you can chain like v.pb(1).pb(2).pb(3); but may be too much work for such small gains.
#include <iostream>
#include <vector>
template<typename T>
class chain
{
private:
std::vector<T> _v;
public:
chain& pb(T a) {
_v.push_back(a);
return *this;
};
std::vector<T> get() { return _v; };
};
using namespace std;
int main(int argc, char const *argv[])
{
chain<int> v{};
v.pb(1).pb(2).pb(3);
for (auto& i : v.get()) {
cout << i << endl;
}
return 0;
}
1
2
3
The simplest, ergonomic way (with C++ 11 or later):
auto my_ints = {1,2,3};
In case you want to have it in your own class:
#include <initializer_list>
Vector<Type>::Vector(std::initializer_list<Type> init_list) : _size(init_list.size()),
_capacity(_size),
_data(new Type[_size])
{
int idx = 0;
for (auto it = init_list.begin(); it != init_list.end(); ++it)
_data[idx++] = *it;
}