It seems to me that I should be able to use std::begin() and std::end() to convert ArrayXd to std::vector<double>; however, when I tried it in the following code, my attempt failed. My understanding is that .data() method on any Eigen object returns a pointer to a continuous block of memory similar to c style array. Therefore, since I can use std::begin(), std::end() on a c style array, I expected that to work with .data() as well. However, Eigen classes are templated, and I think this is what causes me problems, but don't see a way to fix this. How should this be done?
#include <iostream>
#include <vector>
#include <Eigen/Dense>
using namespace Eigen;
int main()
{
ArrayXd e_array(5);
e_array << 3,4,5,6,7;
double c_array[] = {1,2,3,4,5};
//Fails
// std::vector<double> my_vec(std::begin(e_array.data()), std::end(e_array.data()));
// Works
// std::vector<double> my_vec(e_array.data(), e_array.data() + 5);
// Works
// std::vector<double> my_vec(std::begin(c_array), std::end(c_array));
// Works
// std::vector<double> my_vec(c_array, c_array + 5);
return 0;
}
My error message(First lines, the whole message is long):
error: no matching function for call to
‘begin(Eigen::PlainObjectBase >::Scalar*)’
std::vector my_vec(std::begin(e_array.data()),
std::end(e_array.data()))
std::begin(vec.data()) cannot work because data() returns a raw pointer which cannot convey the number of elements in the vector. This version is the best one of yours:
std::vector<double> my_vec(e_array.data(), e_array.data() + 5);
And slightly better:
std::vector<double> my_vec(e_array.data(), e_array.data() + e_array.size());
And you may also be able to do this with many containers, but not with Eigen's ArrayXd in particular, because it lacks begin() and end() (related: http://eigen.tuxfamily.org/bz/show_bug.cgi?id=231).
std::vector<double> my_vec(foo.begin(), foo.end());
Related
By design forward and reverse iterators and ranges are fundamentally different types. This is nice in the compile time optimization that it allows for. Sometimes it would be nice to hide that type difference behind an abstraction that allows them to be passed to the same run-time interface.
Are there any adapters in boost or the stl that make this easy? (ideally but not strictly C++11)
The following code shows both the known/expected failure and the desired hypothetical:
#include <boost/range.hpp>
#include <vector>
using Ints = std::vector<int>;
void real(boost::iterator_range<Ints::iterator> range){}
void fake(boost::agnostic_range<Ints::iterator> range){} // imaginary desired
int main()
{
auto ints = Ints{1,2,3,4,5};
real(boost::make_iterator_range(ints.begin(), ints.end()));
real(boost::make_iterator_range(ints.rbegin(), ints.rend())); // Error
fake(boost::make_agnsotic_range(ints.begin(), ints.end())); // imaginary
fake(boost::make_agnsotic_range(ints.rbegin(), ints.rend())); // imaginary
return 0;
}
Yes! Boost::any_range type erases the iterated object type and exposes only the output type and the iterator access type.
Note that the type erasure here requires a call through a virtual function to dereference the iterator so there's a performance cost there, but as long as non-trivial operations are performed inside the loop, this cost will be likely irrelevant.
BUG WARNING: boost::range had a big bug between ~1.55ish until release 1.74 (2020-08) which would cause access to destroyed items being passed through any_range that would cause UB (undefined behavior/probably crash) The work around to this exists in the code below where you explicitly pass the so-called reference type though the template parameters as const which causes some of the internal machinery to avoid tripping over the mistake.
#include <boost/range/adaptor/type_erased.hpp>
#include <boost/range/adaptor/reversed.hpp>
#include <boost/range/any_range.hpp>
#include <vector>
#include <list>
#include <iostream>
// note const int bug workaround
using GenericBiDirIntRange =
boost::any_range<int, boost::bidirectional_traversal_tag, const int>;
void possible(GenericBiDirIntRange const &inputRange) {
for(auto item: inputRange)
std::cout << item << "\n";
}
// note const int bug workaround
using type_erased_bi =
boost::adaptors::type_erased<int, boost::bidirectional_traversal_tag, const int>;
using reversed = boost::adaptors::reversed;
auto main() -> int {
auto intVec = std::vector<int>{1, 2, 3, 4};
auto intList = std::list<int>{1, 2, 3, 4};
possible(intVec | type_erased_bi());
possible(intList | reversed | type_erased_bi());
return 0;
}
I have a really large valarray that I need to convert to a vector because a library I'm using only takes a vector as input. I'm wondering if it's possible to convert from valarray to vector without copying. Here's what I have:
#include <vector>
#include <valarray>
int main() {
std::valarray<double> va{ {1, 2, 3, 4, 5} };
//Error: cannot convert from 'initializer list' to 'std::vector<eT,std::allocator<_Ty>>'
//std::vector<double> v1{ std::begin(va), va.size() };
//Error: cannot convert from 'std::valarray<double>' to 'std::vector<eT,std::allocator<_Ty>>'
//std::vector<double> v2{ std::move(va) };
// Works but I'm not sure if it's copying
std::vector<double> v3;
v3.assign(std::begin(va), std::end(va));
}
The documentation on assign says that the function "assigns new contents to the vector, replacing its current contents, and modifying its size accordingly.". This sounds to me like it copies. Is there a way to do it without copying?
No, I am afraid it is not possible to convert a valarray to a vector without copying.
Your options are:
Convert your existing codebase to use vector, and use expression templates to retain most of the benefits of valarray.
Convert the library to use valarray.
Copy.
I would start with option 3 and just copy.
Is there any std container which would be fixed size like std::array, but the size would not be compile time, but runtime?
I want to pass a part of some data I have stored in std::array to std::acculumate and similar functions. I do not want to use std::vector (working on embedded platform), therefore I am looking for something in between.
Assume code like this, what I want is something to be used in place of array_part:
#include <array>
#include <algorithm>
#include <iostream>
#include <numeric>
#include <vector>
int main()
{
std::array<float,100> someData;
// fill the data
int dataCount = 50;
std::array_part<float> partOfData(someData.data(),dataCount)); // <<<<< here
const auto s_x = std::accumulate(partOfData.begin(), partOfData.end(), 0.0);
}
If there is no such container, how can I wrap the raw data I have and present them to std::accumulate and other std algorithms?
std::accumulate takes iterators. You can pass it iterators that contain the range of interest:
auto start = partOfData.begin() + 42;
auto end = partOfData.begin() + 77;
const auto s_x = std::accumulate(start, end, 0.0);
Alternatively, you can roll out your own non-owning container-like object. See this question for an example.
Well I am questioning myself if there is a way to pass a vector directly in a parameter, with that I mean, like this:
int xPOS = 5, yPOS = 6, zPOS = 2;
//^this is actually a struct but
//I simplified the code to this
std::vector <std::vector<int>> NodePoints;
NodePoints.push_back(
std::vector<int> {xPOS,yPOS,zPOS}
);
This code ofcourse gives an error; typename not allowed, and expected a ')'
I would have used a struct, but I have to pass the data to a Abstract Virtual Machine where I need to access the node positions as Array[index][index] like:
public GPS_WhenRouteIsCalculated(...)
{
for(new i = 0; i < amount_of_nodes; ++i)
{
printf("Point(%d)=NodeID(%d), Position(X;Y;Z):{%f;%f;%f}",i,node_id_array[i],NodePosition[i][0],NodePosition[i][1],NodePosition[i][2]);
}
return 1;
}
Ofcourse I could do it like this:
std::vector <std::vector<int>> NodePoints;//global
std::vector<int> x;//local
x.push_back(xPOS);
x.push_back(yPOS);
x.push_back(zPOS);
NodePoints.push_back(x);
or this:
std::vector <std::vector<int>> NodePoints;//global
std::vector<int> x;//global
x.push_back(xPOS);
x.push_back(yPOS);
x.push_back(zPOS);
NodePoints.push_back(x);
x.clear()
but then I'm wondering which of the two would be faster/more efficient/better?
Or is there a way to get my initial code working (first snippet)?
Use C++11, or something from boost for this (also you can use simple v.push_back({1,2,3}), vector will be constructed from initializer_list).
http://liveworkspace.org/code/m4kRJ$0
You can use boost::assign as well, if you have no C++11.
#include <vector>
#include <boost/assign/list_of.hpp>
using namespace boost::assign;
int main()
{
std::vector<std::vector<int>> v;
v.push_back(list_of(1)(2)(3));
}
http://liveworkspace.org/code/m4kRJ$5
and of course you can use old variant
int ptr[1,2,3];
v.push_back(std::vector<int>(ptr, ptr + sizeof(ptr) / sizeof(*ptr));
If you don't have access to either Boost or C++11 then you could consider quite a simple solution based around a class. By wrapping a vector to store your three points within a class with some simple access controls, you can create the flexibility you need. First create the class:
class NodePoint
{
public:
NodePoint( int a, int b, int c )
{
dim_.push_back( a );
dim_.push_back( b );
dim_.push_back( c );
}
int& operator[]( size_t i ){ return dim_[i]; }
private:
vector<int> dim_;
};
The important thing here is to encapsulate the vector as an aggregate of the object. The NodePoint can only be initialised by providing the three points. I've also provided operator[] to allow indexed access to the object. It can be used as follows:
NodePoint a(5, 6, 2);
cout << a[0] << " " << a[1] << " " << a[2] << endl;
Which prints:
5 6 2
Note that this will of course throw if an attempt is made to access an out of bounds index point but that's still better than a fixed array which would most likely seg fault. I don't see this as a perfect solution but it should get you reasonably safely to where you want to be.
If your main goal is to avoid unnecessary copies of vector<> then here how you should deal with it.
C++03
Insert an empty vector into the nested vector (e.g. Nodepoints) and then use std::swap() or std::vector::swap() upon it.
NodePoints.push_back(std::vector<int>()); // add an empty vector
std::swap(x, NodePoints.back()); // swaps contents of `x` and last element of `NodePoints`
So after the swap(), the contents of x will be transferred to NodePoints.back() without any copying.
C++11
Use std::move() to avoid extra copies
NodePoints.push_back(std::move(x)); // #include<utility>
Here is the explanation of std::move and here is an example.
Both of the above solutions have somewhat similar effect.
I'm using boost for matrix and vector operations in a code and one of the libraries I am using (CGNS) has an array as an argument. How do I copy the vector into double[] in a boost 'way', or better yet, can I pass the data without creating a copy?
I'm a bit new to c++ and am just getting going with boost. Is there a guide I should read with this info?
Contents between any two input iterators can be copied to an output iterator using the copy algorithm. Since both ublas::vector and arrays have iterator interfaces, we could use:
#include <boost/numeric/ublas/vector.hpp>
#include <algorithm>
#include <cstdio>
int main () {
boost::numeric::ublas::vector<double> v (3);
v(0) = 2;
v(1) = 4.5;
v(2) = 3.15;
double p[3];
std::copy(v.begin(), v.end(), p); // <--
printf("%g %g %g\n", p[0], p[1], p[2]);
return 0;
}
Depends on the types involved. For std::vector you just make sure that it's non-empty and then you can pass &v[0]. Most likely the same holds for the Boost types you're using.