how to avoid copying in boost range transform - c++

boost range transform requires const & for ranges in arguments.
#include <iostream>
#include <vector>
#include <boost/range/algorithm.hpp>
int main(int argc, char *argv[])
{
using namespace std;
vector<vector<int>> rt0(10,vector<int>(15,2));
vector<vector<int>> irt(10,vector<int>(15,5));
for(auto & i:rt0) {
for(auto& j:i) cout << j << " ";
cout << "\n";
}
cout << "\n";
for(auto & i:irt) {
for(auto& j:i) cout << j << " ";
cout << "\n";
}
boost::transform(rt0,irt,rt0.begin(),
[] (const vector<int> &t0,const vector<int> &it) {
auto tt = t0;
boost::transform(t0,it,tt.begin(), plus<int>());
return tt;
}
);
cout << "\n";
cout << "\n";
for(auto & i:rt0) {
for(auto& j:i) cout << j << " ";
cout << "\n";
}
return 0;
}
compile and run with
g++ -std=c++11 main.cc; ./a.out
if boost::transform's BinaryOperation took & instead of const & for SinglePassRange1 then i wouldn't have needed to create a copy (auto tt = t0) and just use to instead of tt. is there a way to avoid creating this copying (while still using ranges)?
link to boost range transform: http://www.boost.org/doc/libs/1_53_0/libs/range/doc/html/range/reference/algorithms/mutating/transform.html

I need to use for_each either with a tuple or the new boost implementation that takes two arguments.
conceptually transform should not modify. it comes from functional programming where there is no in-place modification.

Related

C++20 Coroutines and iostream

I am playing around with C++ 20's Coroutines. The sample is compiled with clang++.
The compiler error I am facing is
error: invalid operands to binary expression ('std::ostream' (aka
'basic_ostream') and 'cppcoro::generator')
which is about the following line
std::cout << numbers << " ";
the full code snipped looks like this:
#include <thread>
#include <iostream>
#include <vector>
#include <cppcoro/generator.hpp>
using namespace std;
// coroutine
cppcoro::generator<int> generatorForNumbers(int begin, int inc = 1)
{
// for Schleife ohne Abbruchbedingung
for (int i = begin;; i += inc)
{
co_yield i;
}
}
int main()
{
auto numbers = generatorForNumbers(-10);
for (int i= 1; i <= 20; ++i)
{
std::cout << numbers << " ";
}
std::cout << "\n\n";
// inline works
for (auto n: generatorForNumbers(0, 5))
{
std::cout << n << " ";
}
std::cout << std::endl;
}
Executable code snipped can be found here:
https://godbolt.org/z/4cxhqxPP7
From the documentation of cppcoro::generator, the only "meaningful" operations you can do to a generator is get begin and end iterators via begin() and end(). This is precisely why your second use for (auto n : generatorForNumbers(0, 5)) works. It iterates over the generator. Though you technically hit undefined behavior since there's no stopping condition for the generator so it overflows an int.
You can't print the generator directly. You have to iterate over it. So you could do this instead:
auto numbers = generatorForNumbers(-10);
auto it = numbers.begin();
for (int i= 1; i <= 20; ++i)
{
std::cout << *it << " ";
++it;
}
or better (in my opinion):
int i = 0;
for (auto n : generatorForNumbers(-10))
{
if (++i > 20)
break;
std::cout << n << " ";
}
or even better using ranges (thanks to #cigien in the comments):
for (auto n : generatorForNumbers(-10) | std::views::take(20))
{
std::cout << n << " ";
}

How do I iterate vector

I have such a code
#include <iostream>
#include <vector>
#include <string>
using namespace std;
void removeFirstFromVec(vector<int> & vecLink) {
// remore first element from some vector
vecLink.erase(vecLink.begin() + 0);
}
int main()
{
vector<int> myVec;
myVec.push_back(1);
myVec.push_back(2);
myVec.push_back(3);
cout << "Before removal\n";
for (auto & i : myVec) {
cout << myVec[i-1] << endl;
}
removeFirstFromVec(myVec);
cout << "After removal\n";
for (auto & i : myVec) { // starts with 2
cout << myVec[i-1] << endl;
}
return 0;
}
But on the place where I put a comment it starts with 2 instead of 0 and it causes an error. What I've done wrong or is there a way to use something brief like auto & i : myVec instead of for (int i = 0; i < ...size(); i++) without such an error
In the range-based for loop
for (auto & i : myVec) {
cout << myVec[i-1] << endl;
}
i is the element of the vector, not the index. It should be
for (auto & i : myVec) {
cout << i << endl;
}
Iteration returns the items themselves, not indices.
vector<int> vec { 5, 3, 2 };
for (int i: vec) {
cout << i << endl;
}
Will output this:
5
3
2
If you do the following:
Use templated-function to accept any type for the vector.
Use direct initialization method rather than push_back() to avoid huge number of lines.
Braces for single syntax is optional. Avoid it to reduce confusion during coding complex programs.
Then you can write the same code in a better manner (don't forget the comments):
#include <iostream>
#include <vector>
using namespace std;
// defining a templated-function
template<class T>
void removeFirstFromVec(vector<T>& vecLink) {
vecLink.erase(vecLink.begin());
}
int main(void) {
// initializing with direct-initialization method
vector<int> myVec {1, 2, 3};
cout << "Before removal\n";
// no braces
for (auto& i : myVec)
// 'i' isn't an index here, it's an element
cout << i << endl;
removeFirstFromVec(myVec);
cout << "After removal\n";
// no braces
for (auto& i : myVec)
cout << i << endl;
return 0;
}

Shortest solution to permute the elements of a std::vector using stl

Assume that you have an std::vector<T> of some type T and a selection of indices std::vector<int> of this vector. Now I'm looking for a function permute(const std::vector<T>& vector, const std::vector<int>& indices), that returns the permuted vector with respect to the given indices.
The problem is easily solved by writing a short function like depicted below:
template<typename T>
std::vector<T> permute(const std::vector<T>& matrix, const std::vector<int>& indices) {
std::vector<T> ret;
for (auto p : indices) {
ret.push_back(matrix[p]);
}
return ret;
}
int main(int, char**) {
std::vector<int> perm{ 1,2,0 };
std::vector<std::vector<double>> matrix = { {1.,2.,3.},{4.,5.,6.},{7.,8.,9.} };
auto matrixPerm=permute(matrix, perm);
std::cout << matrixPerm[0][0] << " == " << matrix[1][0] << std::endl;
std::cout << matrixPerm[1][0] << " == " << matrix[2][0] << std::endl;
std::cout << matrixPerm[2][0] << " == " << matrix[0][0] << std::endl;
}
I'm now wondering what might be most elegant version of this program, if we can use STL or even the Boost libraries. In STL for example we have shuffle(), but we cannot say in what way to shuffle.
Does anyone now, how to shorten the function?
Solution using std::transform()
#include <vector>
#include <iostream>
#include <iterator>
#include <algorithm>
int main(int, char**) {
std::vector<int> perm{ 1,2,0 };
std::vector<std::vector<double>> matrix = { {1.,2.,3.},{4.,5.,6.},{7.,8.,9.} };
std::vector<std::vector<double>> output;
std::transform(perm.begin(), perm.end(), std::back_inserter(output), [&](int i) { return matrix[i]; });
std::cout << output[0][0] << " == " << matrix[1][0] << std::endl;
std::cout << output[1][0] << " == " << matrix[2][0] << std::endl;
std::cout << output[2][0] << " == " << matrix[0][0] << std::endl;
}
You can transform the indices into iterators and then create an indirect range with Boost.Range.
#include <iostream>
#include <iterator>
#include <algorithm>
#include <boost/range/adaptor/indirected.hpp>
#include <boost/range/adaptor/transformed.hpp>
#include <boost/range/algorithm/copy.hpp>
int main(int, char**) {
using namespace boost::adaptors;
std::vector<int> perm{ 1,2,0 };
std::vector<std::vector<double>> matrix = { {1.,2.,3.},{4.,5.,6.},{7.,8.,9.} };
std::vector<std::vector<double>> output;
auto permutation = perm | transformed( [&matrix](int x) { return matrix.begin() + x; }) | indirected;
boost::copy(
permutation,
std::back_inserter(output));
std::cout << output[0][0] << " == " << matrix[1][0] << std::endl;
std::cout << output[1][0] << " == " << matrix[2][0] << std::endl;
std::cout << output[2][0] << " == " << matrix[0][0] << std::endl;
}
You could skip copying the elements and just process the range if you don't need a real vector.
The range adaptor uses the permutation iterator from the Boost.Iterator library. You can also use this directly, but you have to manually define begin and end:
auto begin = make_permutation_iterator( matrix.begin(), perm.begin() );
auto end = make_permutation_iterator( matrix.end(), perm.end() );
std::copy(begin, end, std::back_inserter(output) );

how do I get sequence of 'false' in an array

I am the beginner of C++, and any help will be very appreciated.
here is the code i can run successfully:
#include <Eigen/Dense>
#include <iostream>
using namespace Eigen;
main(){
bool findIn=false;
RowVectorXd A(10);
A<<false,true,false,true,true,false,false,false,true,true;
std::cout << A << std::endl;
for (int i=0;i<A.size();i++){
if(A(i)==findIn){
std::cout << i << std::endl;
}
}
system("pause");
}
the result is {0,2,5,6,7}, and I want to design a function, the code is as follows:
int seq(bool findIn, VectorXd &resdX){
VectorXd A;
for(int i=0;i<resdX.size();i++){
if(resdX(i)==findIn){
A =A+i;
}
}
return(A);
}
I want this function to return result like that {0,2,5,6,7}.But I don`t know how to set up a array to save the result or is there a function just like 'which' in R software to produce sequence above.
Sounds like you want a vector of integers:
#include <vector>
std::vector<int> seq(bool findIn, VectorXd &resdX)
{
std::vector<int> v;
for(int i=0;i<resdX.size();i++) {
if (resdX(i) == findIn) {
v.push_back(i);
}
}
return v;
}
You can then print its contents by iterating through it:
std::vector<int> result = seq(false, A);
for (int i : result) std::cout << i << '\n';
I did not understand what are you looking for.
If you want just to print a sequence of integers indexing findIn values you might code:
void seq(bool findIn, VectorXd &resdX) { // not int
std::cout << "{ ";
for(int i=0;i<resdX.size();i++) // go inside the array
if(resdX(i)==findIn) // if you find that resdX(i) value equals findIn value
std::cout << i << " "; // print i index
std::cout << "}" << std::endl; // at the end prints a new line
}
EDIT1:
Try to adapt the following snippet:
#include <list>
...
std::list<int> seq(bool findIn, VectorXd& resdX) {
std::list<int> l;
for(int i=0; i<resdX.size(); i++) {
if (resdX(i) == findIn) {
l.push_back(i);
}
}
return l;
}
void print_seq(std::list<int> list_) {
std::cout << "{ ";
std::list<int>::iterator it = list_.begin();
for (; it != list_.end(); ++it) {
std::cout << i << " ";
}
std::cout << " }\n";
}

Replace BOOST_FOREACH with "pure" C++11 alternative?

Is it possible to replace the BOOST_FOREACH in this example with a "pure" C++11 equivalent?
#include <map>
#include <functional>
#include <boost/foreach.hpp>
#include <iostream>
int main() {
std::map<int, std::string> map = {std::make_pair(1,"one"), std::make_pair(2,"two")};
int k;
std::string v;
BOOST_FOREACH(std::tie(k, v), map) {
std::cout << "k=" << k << " - " << v << std::endl;
}
}
The key feature being keeping the key/value pair in the references to k and v.
I tried:
for(std::tie(k,v) : map)
{
std::cout << "k=" << k << " - " << v << std::endl;
}
and
auto i = std::tie(k,v);
for(i : map)
{
std::cout << "k=" << k << " - " << v << std::endl;
}
But none of the ranged based for loop ideas seemed to work. Presumably the ranged based for loop is required to have a declaration before the :, since even:
std::vector<int> test;
int i;
for (i : test);
Isn't valid.
The closest equivalent I can find is:
for (auto it = map.begin(); it!=map.end() && (std::tie(k,v)=*it,1); ++it)
{
std::cout << "k=" << k << " - " << v << std::endl;
}
which isn't quite as succinct as the BOOST_FOREACH version!
Is there a way to express the same thing succinctly without boost in C++11?
for (auto & i : map)
{
std::tie(k,v) = i;
// your code here
}
This produces the same output as the Boost macro
for( auto const& k : map ) {
std::cout << "k = " << k.first << " - " << k.second << std::endl;
}
With C++17 this can now be done using structured bindings, for instance:
#include <map>
#include <string>
#include <iostream>
int main() {
const std::map<std::string, std::string> map = {std::make_pair("hello", "world")};
for (auto& [k,v]: map) {
std::cout << "k=" << k << ", v=" << v << "\n";
}
}
This is certainly what I'd choose to do in newer projects.