Reputation: 5231
Writing an interface, I have to convert instances of std::vector<double>
to boost::array<double,N>
. Each time, by construction (without bug), I'm sure the vector has the right size.
Here is an example of what I'm currently doing (I have about 100 such functions to write in the interface) :
double foo1(const std::vector<double>& x)
{
assert(x.size() == 4);
boost::array<double,4> x_;
for(std::size_t i = 0; i < 4; ++i)
x_[i] = x[i];
return foo1_(x_);
}
double foo2(const std::vector<double>& x)
{
assert(x.size() == 6);
boost::array<double,6> x_;
for(std::size_t i = 0; i < 6; ++i)
x_[i] = x[i];
return foo2_(x_);
}
Is there a shorter way to do that ?
Note 1: I don't use C++11 for compatibility reasons.
Note 2: I added tag stdarray
because it can maybe help even if it's a C++11 tag.
Upvotes: 2
Views: 3173
Reputation: 15085
Something like this:
#include <boost/array.hpp>
#include <vector>
#include <boost/range/algorithm.hpp>
#include <iostream>
#include <cassert>
template<size_t Size, class Container>
boost::array<typename Container::value_type, Size> as_array(const Container &cont)
{
assert(cont.size() == Size);
boost::array<typename Container::value_type, Size> result;
boost::range::copy(cont, result.begin());
return result;
}
int main()
{
// this is C++11 initialization, but the rest of code is C++03-complient
std::vector<int> v{1, 2, 3};
boost::array<int, 3> a = as_array<3>(v);
boost::range::copy(a, std::ostream_iterator<int>(std::cout,", "));
}
But keep in mind that such a "translation" from a run-time to a compile-time container might be quite dangerous, as its correctness relies on assert
, which is eliminated in release mode.
Upvotes: 5
Reputation: 63402
You can template over the number of elements (That's what array<>
is doing too). If you order the parameters sensibly, you can specify just the size and have double
still deduced
template<std::size_t N, typename T>
boost::array<T, N> from_vector(const std::vector<T> & vec)
{
assert(x.size() == N);
boost::array<T, N> res;
std::copy(vec.begin(), vec.end(), res.begin());
return res;
}
Which gets used
double foo1(const std::vector<double> & vec)
{
return foo1_(from_vector<4>(vec));
}
double foo2(const std::vector<double> & vec)
{
return foo2_(from_vector<6>(vec));
}
But a better idea would be to re-implement foo1_
and foo2_
in terms of iterators (or something like gsl::span
). You can assert(std::distance(begin, end) == 4)
as needed
Upvotes: 2
Reputation: 44288
Write a template function:
template<class T,size_t N>
std::array<T,N> convert( const std::vector<T> & v )
{
//assert(v.size() == N);
std::array<T,N> r;
std::copy( v.begin(), v.end(), r.begin() );
return r;
}
then your functions will become one liners:
double foo1(const std::vector<double>& x)
{
return foo1_( convert<double,4>( x ) );
}
Upvotes: 2