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.
Related
First one being:
map <int,int> m;
//... some elements inserted
auto i= m.begin();
cout<<(*i).first<<(*i).second;
Here we are required to use the dereference operator *
Second:
map <int,int> m;
//... some elements inserted
for(auto i: m)
cout<<i.first<<i.second;
Why am I not required to use the * operator this time?
One more doubt:
for(auto &i: m)
what difference does '&' make here?
auto i=m.begin() will give you iterator .. which is accessed more like a pointer (syntactically) when you want to access the value...
for(auto i:m) will copy current element of m (a pair) into i , i is a copy of element, not the element itself...
for (auto &i: m) will work on a reference, the original map is affected
As explained in the below code snippet, the first i is of type iterator where as the i in the for loops are of pair type.
#include <iostream>
#include <map>
int main()
{
std::map <int,int> m;
m[1] = 5;
m[10] = 60;
m[100] = 800;
// Below i is map iterator (std::map<int, int>::iterator)
auto i = m.begin();
std::cout << typeid(i).name() << '\n';
std::cout << (*i).first << " : " << (*i).second << '\n';
std::cout << i->first << " : " << i->second << '\n';
for(auto i: m) {
// Below i is pair<int, int>
std::cout << typeid(i).name() << '\n';
std::cout << i.first << " : " << i.second << '\n';
}
for(auto& i: m) {
// Below i is reference of pair<int, int>)
// modifying this would result in updated values in the map.
std::cout << typeid(i).name() << '\n';
std::cout << i.first << " : " << i.second << '\n';
}
return 0;
}
Ex:
vector<string> myVec = {apple, banana, grape}
How can I print these elements as an ordered list using a range-based loop
Output:
1 apple
2 banana
3 grape
A variation of Jeffrey's answer, but without additional variable:
for (const auto& s : myVec)
{
std::cout << &s - &myVec[0] << " " << s << "\n";
}
This, of course, prints a "correct" 0-based index. Feel free to add 1 to it :)
Using boost ranges really simplifies things Live Demo
using namespace boost::adaptors;
std::vector<std::string> myVec = {"apple", "banana", "grape"};
for (const auto& element : myVec | indexed(1))
{
std::cout << element.index() << " " << element.value() << "\n";
}
Produces
1 apple
2 banana
3 grape
You are looking for
size_t position = 1;
for(const auto& s: myVec)
{
std::cout << position << " " << s << "\n";
position++;
}
as in
#include <iostream>
#include <string>
#include <vector>
using std::vector;
using std::string;
vector<string> myVec = {"apple", "banana", "grape"};
int main()
{
size_t position = 1;
for(const auto& s: myVec)
{
std::cout << position << " " << s << "\n";
position++;
}
}
With range-v3, you could write:
for (auto [i, val] : myVec | ranges::views::enumerate)
{
std::cout << i << ' ' << val << "\n";
}
Here's a demo.
This would be a good issue for the original for loop:
const size_t quantity = myVec.size();
for (unsigned int i = 0; i < quantity; ++i)
{
cout << (i + 1) << " " << myVec[i] << "\n";
}
Simple, effective. Don't knock the old stuff. :-)
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) );
I've got multiple containers of different types.
I'd like to perform the same action on all of the elements across all the containers.
Normally, this involves multiple range-based for loops with duplicated code:
#include <iostream>
#include <vector>
#include <set>
int main() {
//containers
std::vector<int> v1{1,2,3,4,5};
std::set<float> v2{6,7,8,9,10};
//perform iterations
for (auto & it: v1){
std::cout << it << ' ';
}
for (auto & it: v2){
std::cout << it << ' ';
}
}
I'd like to be able to do this instead,
by providing multiple containers to the same range-based for loop.
This of course does not work:
for (auto & it: v1,v2){
std::cout << it << ' ';
}
Is there a library solution I could use to achieve this?
You could use boost range's combine:
for(auto&& el : boost::combine(v1, v2)) {
std::cout << boost::get<0>(el) << ", " << boost::get<1>(el) << '\n';
}
demo
Or, range-v3's zip view:
for(auto&& el : view::zip(v1, v2)) {
std::cout << std::get<0>(el) << ", " << std::get<1>(el) << '\n';
}
demo
Alternatively, you could make a range from zip iterators the hard way:
auto b = boost::make_zip_iterator(boost::make_tuple(v1.begin(), v2.begin()));
auto e = boost::make_zip_iterator(boost::make_tuple(v1.end(), v2.end()));
for(auto&& tup : boost::make_iterator_range(b, e)) {
std::cout << boost::get<0>(tup) << ", " << boost::get<1>(tup) << '\n';
}
demo
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.