I have defined a vector of the boundary_info structure as std::vector<boundary_info> nodes to be used in my code for a specific purpose. While I try to push_back new elements into this vector in a specific function as:
void myFun()
{
std::vector<float_type> dists(9, -1.0);
std::array<float_type,9> f, g;
//do something - x and y are defined here
nodes.push_back(boundary_info{point<int>{x,y}, dists, f, g, {}});
}
I get the following error message :
Error 1 : cannot convert ‘std::vector<float>’ to ‘float’ in initialization
Error 2 : cannot convert ‘std::array<float, 9ul>’ to ‘float’ in
initialization
Error 3 : cannot convert ‘std::array<float, 9ul>’ to ‘float’ in
initialization
Error 1 is associated with dists, which is a vector. Errors 2 and 3 are associated with the f, g passed as parameters in push_back respectively.
The code is shown below.
#include <iostream>
#include <vector>
template <typename T>
struct point //specify a point structure
{
T x,y;
};
struct boundary_info
{
point<int> xy_bdary; //coordinates of a bdary point
std::array<float_type,9> dist; //distance from boundary
std::array<float_type,9> f_prev, g_prev; //populations
std::vector<int> miss_dirns; //missing directions
};
I would be glad if the solution for this error would be pointed out. I have been struggling with it since half a day.
Note : I am compiling using c++11.
Edit
You can find a minimal code of this problem reproducing the same problem at
https://repl.it/repls/GleefulTartMarkuplanguage
Thanks
In the following line you are trying to initialize a std::array (boundary_info::dist) from a std::vector (dists):
nodes.push_back(boundary_info{point<int>{x,y}, dists, f, g, {}});
std::array doesn't have a constructor that accepts a std::vector. You could only initialize the std::array element-wise (aggregate initialization) or explicitly copy the std::vector to the std::array.
Aggregate initialization
nodes.push_back(boundary_info{point<int>{x,y}, {dists[0], dists[1], dists[2], dists[3], dists[4], dists[5], dists[6], dists[7], dists[8]}, f, g, {}});
Of course, that's not very elegant.
Copy std::vector to std::array
With the help of a little template function, we can do better.
template<typename T, std::size_t N, typename Range>
std::array<T,N> to_array( Range const& in )
{
std::array<T,N> result;
// To make the standard begin() and end() in addition to any user-defined
// overloads available for ADL.
using std::begin; using std::end;
std::copy( begin( in ), end( in ), result.begin() );
return result;
}
Live demo
to_array accepts any input type that has begin() and end() member functions or overloads of the free functions begin() and end().
Now you can initialize the array from the vector like this:
nodes.push_back(boundary_info{point<int>{x,y}, to_array<float_type,9>(dists), f, g, {}});
Note that you can easily shoot yourself in the foot if dists has more elements than the array, because to_array doesn't do any range checking (std::copy doesn't do either). I'll leave it as an exercise for the reader to make the function more secure, if needed.
Related
I try to implement that summing up all elements of a vector<vector<int>> in a non-loop ways.
I have checked some relevant questions before, How to sum up elements of a C++ vector?.
So I try to use std::accumulate to implement it but I find it is hard for me to overload a Binary Operator in std::accumulate and implement it.
So I am confused about how to implement it with std::accumulate or is there a better way?
If not mind could anyone help me?
Thanks in advance.
You need to use std::accumulate twice, once for the outer vector with a binary operator that knows how to sum the inner vector using an additional call to std::accumulate:
int sum = std::accumulate(
vec.begin(), vec.end(), // iterators for the outer vector
0, // initial value for summation - 0
[](int init, const std::vector<int>& intvec){ // binaryOp that sums a single vector<int>
return std::accumulate(
intvec.begin(), intvec.end(), // iterators for the inner vector
init); // current sum
// use the default binaryOp here
}
);
In this case, I do not suggest using std::accumulate as it would greatly impair readability. Moreover, this function use loops internally, so you would not save anything. Just compare the following loop-based solution with the other answers that use std::accumulate:
int result = 0 ;
for (auto const & subvector : your_vector)
for (int element : subvector)
result += element;
Does using a combination of iterators, STL functions, and lambda functions makes your code easier to understand and faster? For me, the answer is clear. Loops are not evil, especially for such simple application.
According to https://en.cppreference.com/w/cpp/algorithm/accumulate , looks like BinaryOp has the current sum on the left hand, and the next range element on the right. So you should run std::accumulate on the right hand side argument, and then just sum it with left hand side argument and return the result. If you use C++14 or later,
auto binary_op = [&](auto cur_sum, const auto& el){
auto rhs_sum = std::accumulate(el.begin(), el.end(), 0);
return cur_sum + rhs_sum;
};
I didn't try to compile the code though :). If i messed up the order of arguments, just replace them.
Edit: wrong terminology - you don't overload BinaryOp, you just pass it.
Signature of std::accumulate is:
T accumulate( InputIt first, InputIt last, T init,
BinaryOperation op );
Note that the return value is deduced from the init parameter (it is not necessarily the value_type of InputIt).
The binary operation is:
Ret binary_op(const Type1 &a, const Type2 &b);
where... (from cppreference)...
The type Type1 must be such that an object of type T can be implicitly converted to Type1. The type Type2 must be such that an object of type InputIt can be dereferenced and then implicitly converted to Type2. The type Ret must be such that an object of type T can be assigned a value of type Ret.
However, when T is the value_type of InputIt, the above is simpler and you have:
using value_type = std::iterator_traits<InputIt>::value_type;
T binary_op(T,value_type&).
Your final result is supposed to be an int, hence T is int. You need two calls two std::accumulate, one for the outer vector (where value_type == std::vector<int>) and one for the inner vectors (where value_type == int):
#include <iostream>
#include <numeric>
#include <iterator>
#include <vector>
template <typename IT, typename T>
T accumulate2d(IT outer_begin, IT outer_end,const T& init){
using value_type = typename std::iterator_traits<IT>::value_type;
return std::accumulate( outer_begin,outer_end,init,
[](T accu,const value_type& inner){
return std::accumulate( inner.begin(),inner.end(),accu);
});
}
int main() {
std::vector<std::vector<int>> x{ {1,2} , {1,2,3} };
std::cout << accumulate2d(x.begin(),x.end(),0);
}
Solutions based on nesting std::accumulate may be difficult to understand.
By using a 1D array of intermediate sums, the solution can be more straightforward (but possibly less efficient).
int main()
{
// create a unary operator for 'std::transform'
auto accumulate = []( vector<int> const & v ) -> int
{
return std::accumulate(v.begin(),v.end(),int{});
};
vector<vector<int>> data = {{1,2,3},{4,5},{6,7,8,9}}; // 2D array
vector<int> temp; // 1D array of intermediate sums
transform( data.begin(), data.end(), back_inserter(temp), accumulate );
int result = accumulate(temp);
cerr<<"result="<<result<<"\n";
}
The call to transform accumulates each of the inner arrays to initialize the 1D temp array.
To avoid loops, you'll have to specifically add each element:
std::vector<int> database = {1, 2, 3, 4};
int sum = 0;
int index = 0;
// Start the accumulation
sum = database[index++];
sum = database[index++];
sum = database[index++];
sum = database[index++];
There is no guarantee that std::accumulate will be non-loop (no loops). If you need to avoid loops, then don't use it.
IMHO, there is nothing wrong with using loops: for, while or do-while. Processors that have specialized instructions for summing arrays use loops. Loops are a convenient method for conserving code space. However, there may be times when loops want to be unrolled (for performance reasons). You can have a loop with expanded or unrolled content in it.
With range-v3 (and soon with C++20), you might do
const std::vector<std::vector<int>> v{{1, 2}, {3, 4, 5, 6}};
auto flat = v | ranges::view::join;
std::cout << std::accumulate(begin(flat), end(flat), 0);
Demo
this code
std::initializer_list<const char*> list {"something", "somthingElse" /*..*/};
const char* array[] = list;
fails to compile with the following error on error:
array initializer must be an initializer list
Can't really understand what I'm doing wrong here since I'm using an initializer_list after all.
(The reason I use an initializer_list is so I can use list.size() later in my code in several parts; it'd be error_prone having to adjust a series of magic constants each time I add/remove something from the list)
To initialize an array, you need a brace-enclosed initializer list which is not the same as a std::initializer_list.
To get what you're trying to achieve, you could use a std::array, but you'll need a helper function to deduce its size parameter:
#include <array>
template<typename T, typename... Ts>
constexpr std::array<T, sizeof...(Ts)> make_array(Ts... i)
{
return {i...};
}
int main() {
auto a = make_array<const char*>( "a", "b", "c", "d" );
return a.size(); // I get an exit value of 4 here
}
I have a simple point structure
struct mypoint
{
int x;
int y;
};
and a vector of mypoints
vector<mypoint> myvector;
If I want to create a vector of int containing all the coordinates of my points (i.e. x1, y1, x2, y2, x3, y3, ...), I could easily do it in the following way
vector<mypoint>::iterator pt, ptend(myvector.end());
vector<int> newvector;
for(pt=myvector.begin(); pt!=ptend; ++pt)
{
newvector.push_back(pt->x);
newvector.push_back(pt->y);
}
Is there a way to obtain the same result in one (or two) line(s) of code using the C++11?
std::vector<int> extractIntsFromPoints(const std::vector<mypoint>& pointVector)
{
std::vector<int> retVector;
for (const auto& element : pointVector)
{
retVector.push_back(element.x);
retVector.push_back(element.y);
}
return retVector;
}
Call this function where you need the int vector.
I threw in the range-based for loop to make it extra C++11.
Since you're using C++11, you can use the new for syntax.
vector<int> newvector;
for( const auto &pt : myvector)
{
newvector.push_back(pt.x);
newvector.push_back(pt.y);
}
steal from the post: C++ std::transform vector of pairs->first to new vector
vector<int> items;
std::transform(pairs.begin(),
pairs.end(),
std::back_inserter(items),
[](const std::pair<int, int>& p) { return p.first; });
Here's about 4 lines, using a lambda:
vector<mypoint> points;
vector<int> iv;
points.push_back(mypoint(1,2));
points.push_back(mypoint(3,4));
points.push_back(mypoint(5,6));
for_each(points.cbegin(), points.cend(),
[&iv](const mypoint &pt) {
iv.push_back(pt.x);
iv.push_back(pt.y);
});
You could use a std::pair<> in which you push the coordinates using std::make_pair and then push the std::pair<> into the vector such as:
mypoint a_point;
std::pair<int, int> point = std::make_pair(a_point.x, a_point.y);
vector<std::pair<int, int>> vec.push_back(point).
Perhaps bulky but in two lines it works well and encapsulates a point rather than separating the magnitudes of each point axis and placing them inside a std::vector.
As reima already noted, if you only want to reference the existing sequence, it is sufficient to cast myvector.data() to int* (assuming sizeof(mypoint) == 2 * sizeof(int) holds).
However, if you explicitly want a copy of the flattened sequence, you are probably better off creating a small utility function like this:
template <typename T, typename U>
std::vector<T> flatten(std::vector<U> const& other) {
static_assert(std::is_trivially_copyable<U>::value,
"source type must be trivially copyable!");
static_assert(std::is_trivially_copy_constructible<T>::value,
"destination type must be trivially copy constructible!");
static_assert((sizeof(U) / sizeof(T)) * sizeof(T) == sizeof(U),
"sizeof(U) must be a multiple of sizeof(T)!");
return std::vector<T>(reinterpret_cast<T const*>(other.data()),
reinterpret_cast<T const*>(std::next(other.data(), other.size())));
}
template <typename U>
std::vector<typename U::value_type> flatten(std::vector<U> const& other) {
return flatten<typename U::value_type>(other);
}
reducing your code to
auto newvector = flatten<int>(myvector);
or - if you equip your mypoint struct with a (STL-conforming) value_type member type - even to
auto newvector = flatten(myvector);
Note, that this utility function is nothing more than a tweaked constructor using the inherently unsafe reinterpret_cast to convert mypoint pointers into int pointers.
To get rid of the safety caveats that go along with the use of reinterpret_cast, the flatten function uses some static_assert parachutes. So, it's better to hide all this in a seprate function.
Still, it uses a lot of C++11 features like auto, move construction, static_assert, type traits, std::next and vector::data() which pretty much strips down your call site code to a bare minimum.
Also, this is as efficient as it gets because the range constructor of vector will only perform the memory allocation and call uninitialized_copy, which will probably boil down to a call of memcpy for trivially copyable types.
I'm reading the C++ Templates: The complete guide book and in chapter 4 (4.2 Nontype Function Template Parameters) is an example of a template function that can be used with STL containers to add a value to each element of a collection. Here is the complete program:
#include <iostream>
#include <vector>
#include <algorithm>
#include <iterator>
template<typename T, int VAL>
T addValue(T const& x)
{
return x + VAL;
}
int main()
{
std::vector<int> source;
std::vector<int> dest;
source.push_back(1);
source.push_back(2);
source.push_back(3);
source.push_back(4);
source.push_back(5);
std::transform(source.begin(), source.end(), dest.begin(), (int(*)(int const&)) addValue<int, 5>);
std::copy(dest.begin(), dest.end(), std::ostream_iterator<int>(std::cout, ", "));
return 0;
}
I had to make that ugly cast because the book states that:
Note that there is a problem with this example: addValue<int,5> is a function template, and function templates are considered to name a set of overloaded functions (even if the set has only one member). However, according to the current standard, sets of overloaded functions cannot be used for template parameter deduction. Thus, you have to cast to the exact type of the function template argument:
std::transform (source.begin(), source.end(), // start and end of source
dest.begin(), // start of destination
(int(*)(int const&)) addValue<int,5>); // operation
My problem is that I get an segmentation fault when running the program. I am building it using Clang on the Mac.
Is the cast incorrect or what else could the problem be ?
The cast is not your problem, you are outputting elements to an empty vector. Instead you could resize the space you will need:
dest.resize(source.size());
or better yet let transform figure that out:
std::transform(
source.begin(), source.end()
, std::back_inserter( dest ) // needs <iterator>
, &addValue<int, 5> // cast should not be needed
);
although if you do know how much space it will take, resize-ing the vector will have better performance as it will avoid internal reallocation as items are added. Another alternative is to call reserve to avoid internal reallocation:
dest.reserve(source.size());
// dest is still empty
std::transform(
source.begin(), source.end()
, std::back_inserter( dest ) // needs <iterator>
, &addValue<int, 5> // cast should not be needed
);
The problem of the segmentation fault is that dest is empty but you are assigning values to it! There are two approaches to make sure that there are elements you can actually assign to:
You can set the size of dest before std::transform()ing the data: dest.resize(source.size()).
You can instruct the algorithm to insert objects at the end of dest using a std::back_insert_iterator<...>: std::transform(source.begin(), source.end(), std::back_inserter(dest), function) (where function is a suitable approach to get hold of a function object).
Personally, I wouldn't use a pointer to a function anyway because it is quite likely that compiler won't inline the function call though a pointer to a function anyway. Instead, I'd use a suitable function object:
template <int N>
struct addValue {
template <typename T>
T operator()(T value) const { return value + N; }
};
... and then just use
std::transform(source.begin(), source.end(), std::back_inserter(dest), addValue<5>());
Hi I want to (multiply,add,etc) vector by scalar value for example myv1 * 3 , I know I can do a function with a forloop , but is there a way of doing this using STL function? Something like the {Algorithm.h :: transform function }?
Yes, using std::transform:
std::transform(myv1.begin(), myv1.end(), myv1.begin(),
std::bind(std::multiplies<T>(), std::placeholders::_1, 3));
Before C++17 you could use std::bind1st(), which was deprecated in C++11.
std::transform(myv1.begin(), myv1.end(), myv1.begin(),
std::bind1st(std::multiplies<T>(), 3));
For the placeholders;
#include <functional>
If you can use a valarray instead of a vector, it has builtin operators for doing a scalar multiplication.
v *= 3;
If you have to use a vector, you can indeed use transform to do the job:
transform(v.begin(), v.end(), v.begin(), _1 * 3);
(assuming you have something similar to Boost.Lambda that allows you to easily create anonymous function objects like _1 * 3 :-P)
Modern C++ solution for your question.
#include <algorithm>
#include <vector>
std::vector<double> myarray;
double myconstant{3.3};
std::transform(myarray.begin(), myarray.end(), myarray.begin(), [&myconstant](auto& c){return c*myconstant;});
I think for_each is very apt when you want to traverse a vector and manipulate each element according to some pattern, in this case a simple lambda would suffice:
std::for_each(myv1.begin(), mtv1.end(), [](int &el){el *= 3; });
note that any variable you want to capture for the lambda function to use (say that you e.g. wanted to multiply with some predetermined scalar), goes into the bracket as a reference.
If you had to store the results in a new vector, then you could use the std::transform() from the <algorithm> header:
#include <algorithm>
#include <vector>
int main() {
const double scale = 2;
std::vector<double> vec_input{1, 2, 3};
std::vector<double> vec_output(3); // a vector of 3 elements, Initialized to zero
// ~~~
std::transform(vec_input.begin(), vec_input.end(), vec_output.begin(),
[&scale](double element) { return element *= scale; });
// ~~~
return 0;
}
So, what we are saying here is,
take the values (elements) of vec_input starting from the beginning (vec_input.begin()) to the end (vec_input.begin()),
essentially, with the first two arguments, you specify a range of elements ([beginning, end)) to transform,
range
pass each element to the last argument, lambda expression,
take the output of lambda expression and put it in the vec_output starting from the beginning (vec_output.begin()).
the third argument is to specify the beginning of the destination vector.
The lambda expression
captures the value of scale factor ([&scale]) from outside by reference,
takes as its input a vector element of type double (passed to it by std::transform())
in the body of the function, it returns the final result,
which, as I mentioned above, will be consequently stored in the vec_input.
Final note: Although unnecessary, you could pass lambda expression per below:
[&scale](double element) -> double { return element *= scale; }
It explicitly states that the output of the lambda expression is a double. However, we can omit that, because the compiler, in this case, can deduce the return type by itself.
I know this not STL as you want, but it is something you can adapt as different needs arise.
Below is a template you can use to calculate; 'func' would be the function you want to do: multiply, add, and so on; 'parm' is the second parameter to the 'func'. You can easily extend this to take different func's with more parms of varied types.
template<typename _ITStart, typename _ITEnd, typename _Func , typename _Value >
_ITStart xform(_ITStart its, _ITEnd ite, _Func func, _Value parm)
{
while (its != ite) { *its = func(*its, parm); its++; }
return its;
}
...
int mul(int a, int b) { return a*b; }
vector< int > v;
xform(v.begin(), v.end(), mul, 3); /* will multiply each element of v by 3 */
Also, this is not a 'safe' function, you must do type/value-checking etc. before you use it.