I have a function that currently accepts 2 vectors that can contain any plain old data ...
template <class T>
void addData(const vector<T>& yData, vector<T> xData)
{ .. }
Question:
std::array
or two std::vector
, or even a combination thereof, given that these containers take a different number of template arguments?Difference between std::vector and std::array in C++ Vector is a sequential container to store elements and not index based. Array stores a fixed-size sequential collection of elements of the same type and it is index based. Vector is dynamic in nature so, size increases with insertion of elements.
vector is a template class, which can be instantiated with a type, in the format: vector<int> , vector<double> , vector<string> . The same template class can be used to handle many types, instead of repeatably writing codes for each of the type.
You should not notice any difference in runtime performance while you still get to enjoy the extra features. Using std::array instead of int[] style arrays is a good idea if you have C++11 or boost at hand.
std::array is merely a wrapper around the C-style fixed arrays. to provide type-safety with useful interfaces. Stack-allocation implies that the data for the array is stored in the object itself.
Sure, it's just a matter of creating a suitable type trait. The example just uses a function f()
with one argument but it is trivial to extend to take any number of arguments.
#include <array>
#include <vector>
#include <deque>
#include <utility>
#include <cstddef>
template <typename T>
struct is_array_or_vector {
enum { value = false };
};
template <typename T, typename A>
struct is_array_or_vector<std::vector<T, A>> {
enum { value = true };
};
template <typename T, std::size_t N>
struct is_array_or_vector<std::array<T, N>> {
enum { value = true };
};
template <typename T>
typename std::enable_if<is_array_or_vector<T>::value>::type
f(T const&)
{
}
int main()
{
f(std::vector<int>()); // OK
f(std::array<int, 17>()); // OK
f(std::deque<int>()); // ERROR
}
Why not just use this, which works with any container using random-access iterators, including plain old arrays. If you can use iteration instead of indexing, you can do away with the random-access requirement as well.
template <typename Cnt1, typename Cnt2>
void addData(const Cnt1& yData, Cnt2 xData) // is pass-by-value intended?
{
using std::begin;
using std::end;
typedef decltype(*begin(yData)) T;
const auto sizeY = end(yData) - begin(yData);
const auto sizeX = end(xData) - begin(xData);
// ...
}
C++03 version (doesn't support plain old arrays):
template <typename Cnt1, typename Cnt2>
void addData(const Cnt1& yData, Cnt2 xData) // is pass-by-value intended?
{
typedef Cnt1::value_type T;
const size_t sizeY = yData.end() - yData.begin();
const size_t sizeX = xData.end() - xData.begin();
// ...
}
An alternative solution:
#include <iostream>
#include <vector>
#include <array>
using std::vector;
using std::array;
template <typename Container>
struct container_helper; // undefined
template <typename T>
struct container_helper<vector<T>>
{
explicit container_helper(vector<T>& data)
: _data(data)
{}
T* get_data()
{ return &_data[0]; }
size_t get_size()
{ return _data.size(); }
private:
vector<T>& _data;
};
template <typename T, size_t N>
struct container_helper<array<T,N>>
{
explicit container_helper(array<T,N>& data)
: _data(data)
{}
T* get_data()
{ return &_data[0]; }
size_t get_size()
{ return N; }
private:
array<T,N>& _data;
};
template <typename Container1, typename Container2>
void add_data(Container1& c1, Container2& c2)
{
container_helper<Container1> c1_helper(c1);
container_helper<Container2> c2_helper(c2);
/* do whatever you want with the containers */
std::cout << "c1 size " << c1_helper.get_size() << std::endl;
std::cout << "c2 size " << c2_helper.get_size() << std::endl;
}
int main()
{
vector<int > v_ints(3);
array<int, 2> a_ints;
add_data(v_ints, a_ints);
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With