C++ 11- scopes & global variables - c++11

How can I reach global variables from inner scopes, given the following code sample, how can I reach the global string X from the main function and from the most inner scope as well, also is the most inner scope is accessible once we quit it to the main scope or other scope?
#include <iostream>
#include <string>
std::string x = "global";
int counter = 1;
int main()
{
std::cout <<counter ++ << " " << x << std::endl;
std::string x = "main scope";
std::cout <<counter ++ << " " << x << std::endl;
{
std::cout <<counter ++ << " " << x << std::endl;
std::string x = "inner scope";
std::cout <<counter ++ << " " << x << std::endl;
}
std::cout <<counter++ << " " << x << std::endl;
}
the cout currently is:
1 global
2 main scope
3 main scope
4 inner scope
5 main scope

Global scope can be reached by using ::x, as per:
#include <iostream>
#include <string>
std::string x = "global";
int counter = 1;
int main()
{
std::cout << counter++ << " " << x << std::endl;
std::string x = "main scope";
std::cout << " " << ::x << std::endl;
std::cout << counter++ << " " << x << std::endl;
{
std::cout << " " << ::x << std::endl;
std::cout << counter++ << " " << x << std::endl;
std::string x = "inner scope";
std::cout << " " << ::x << std::endl;
std::cout << counter++ << " " << x << std::endl;
}
std::cout << " " << ::x << std::endl;
std::cout << counter++ << " " << x << std::endl;
}
which gives you:
1 global
global
2 main scope
global
3 main scope
global
4 inner scope
global
5 main scope
The hard bit is actually getting to the intermediate scopes, such as main scope when you're withing the inner scope.
One way to do that is with references:
#include <iostream>
#include <string>
std::string x = "outer";
int main()
{
std::cout << "1a " << x << "\n\n";
std::string x = "middle";
std::cout << "2a " << ::x << '\n';
std::cout << "2b " << x << "\n\n";
{
std::string &midx = x; // make ref to middle x.
std::string x = "inner"; // hides middle x.
std::cout << "3a " << ::x << '\n';
std::cout << "3b " << midx << '\n'; // get middle x via ref.
std::cout << "3c " << x << "\n\n";
}
}
which gives:
1a outer
2a outer
2b middle
3a outer
3b middle
3c inner
But, as good advice, you'll find you won't have anywhere near as many problems if you:
name your variables a little more intelligently so as to avoid clashes; and
avoid global variables like the plague :-)
And, as for the variables in inner scopes, they cease to be available once you leave that scope, even with a reference (you can copy them to a variable with an larger scope but that's not the same as accessing the inner-scoped variable).

Related

Generate C++ string with space behind such that space is automatically adjusted

I am trying to create a text generator which shall generate following output:
localparam OR_CHANNEL_DATA_WIDTH = 2;
localparam RQ_CHANNEL_DATA_WIDTH = 18;
localparam RSP_CHANNEL_DATA_WIDTH = 8;
localparam VIN_CHANNEL_DATA_WIDTH = 43;
localparam VOUT_CHANNEL_DATA_WIDTH = 123;
I used std::stringstream to build the stream:
std::stringstream ss;
ss << "localparam OR_CHANNEL_DATA_WIDTH" << std::right << std::setw(80) << " = " << Sth::get() << ";\n";
ss << "localparam RQ_CHANNEL_DATA_WIDTH" << std::right << std::setw(80) << " = " << Sth::get() << ";\n";
ss << "localparam RSP_CHANNEL_DATA_WIDTH" << std::right << std::setw(80) << " = " << Sth::get() << ";\n";
Sth::get() will return number. There are many such lines that needs to be generated. But the text in the middle is not fixed. How can I achieve the above output
I am not sure you can do it in a simple streaming operation, but easily write a small function that does the job:
#include <iostream>
#include <sstream>
#include <iomanip>
const std::string adjust_width(const std::string& s, int width)
{
std::stringstream temp;
temp << std::left << std::setw(width) << s;
return temp.str();
}
int main()
{
std::stringstream ss;
ss << adjust_width("localparam OR_CHANNEL_DATA_WIDTH", 80) << " = " << 1 << ";\n";
ss << adjust_width("localparam RQ_CHANNEL_DATA_WIDTH", 80) << " = " << 12 << ";\n";
ss << adjust_width("localparam RSP_CHANNEL_DATA_WIDTH", 80) << " = " << 123 << ";\n";
ss << adjust_width("localparam VIN_CHANNEL_DATA_WIDTH", 80) << " = " << 1234 << ";\n";
std::cout << ss.str();
return 0;
}

How to append more items to an existing vector contained in the value field of a std::map?

I have a std::vector<std::string>>. Following is my full program:
#include <iostream>
#include <vector>
#include <string>
#include <map>
int main() {
std::cout << " -- Beginining of program -- " << std::endl;
std::map<std::string, std::vector<std::string>> my_map_2;
std::vector<std::string> s = {"a", "b", "c"};
my_map_2.insert(std::make_pair("key1", s));
std::vector<std::string> s2 = {"d", "e", "f"};
my_map_2.insert(std::make_pair("key1", s2));
for(auto const &map_item: my_map_2) {
std::cout << map_item.first << " " << map_item.second[0] << std::endl;
std::cout << map_item.first << " " << map_item.second[1] << std::endl;
std::cout << map_item.first << " " << map_item.second[2] << std::endl;
std::cout << map_item.first << " " << map_item.second[3] << std::endl;
std::cout << map_item.first << " " << map_item.second[4] << std::endl;
std::cout << map_item.first << " " << map_item.second[5] << std::endl;
}
std::cout << " -- End of program -- " << std::endl;
return 0;
}
Problem:
I don't see the items of s2 when I print values of my_map_2. I see them only if I add s2 with a new key! If I do my_map_2.insert(std::make_pair("key2", s2)) instead of my_map_2.insert(std::make_pair("key1", s2)), I do see the items.
Question:
So, my question is, how to I append more items to the vector pointed to by key1 of my_map_2?
The below fails because the key is already taken:
std::vector<std::string> s2 = {"d", "e", "f"};
my_map_2.insert(std::make_pair("key1", s2)); // fails
To append to the mapped vector, you could do like this:
auto& vec = my_map_2["key1"]; // get reference to the existing vector
vec.insert(vec.end(), s2.begin(), s2.end()); // append to it
To view the keys and all the values in the vector you could change your loop to this:
for(auto const&[key, value]: my_map_2) {
for(const std::string& str : value) {
std::cout << key << ' ' << str << '\n';
}
}
my_map_2["key1"] is always a valid vector. You can insert into it directly
#include <iostream>
#include <vector>
#include <string>
#include <map>
int main() {
std::cout << " -- Beginining of program -- " << std::endl;
std::map<std::string, std::vector<std::string>> my_map_2;
std::vector<std::string> s = {"a", "b", "c"};
my_map_2["key1"].insert(my_map_2["key1"].end(), s.begin(), s.end());
std::vector<std::string> s2 = {"d", "e", "f"};
my_map_2["key1"].insert(my_map_2["key1"].end(), s2.begin(), s2.end());
for(auto const &map_item: my_map_2) {
for(auto const &value: map_item.second) {
std::cout << map_item.first << " " << value << std::endl;
}
}
std::cout << " -- End of program -- " << std::endl;
return 0;
}
Get iterator to key1, and just pushs back new items to existing vector:
std::vector<std::string> s2 = {"d", "e", "f"};
auto it = my_map_2.find("key1");
if (it != my_map_2.end())
std::move(s2.begin(), s2.end(), std::back_inserter(it->second));
else
my_map_2.insert(std::make_pair("key1",std::move(s2)));
To see: d,e,f you have to access 3,4 and 5 indices of vector. (You want to append new items, or just override existed items for given key?)

problem with polygon_90_data and vertices

I create a boost polygon with 5 vertices, but when I display the vertices or
#include <boost/polygon/polygon.hpp>
.
.
.
void displayPolygon(boost::polygon::polygon_90_data<int> const& polygon, std::string name)
{
std::cout << std::endl << "polygon " << name << std::endl;
for (boost::polygon::polygon_90_data<int>::iterator_type it = polygon.begin(); it != polygon.end(); it++)
{
std::cout << (*it).x() << "/" << (*it).y() << "->";
}
std::cout << std::endl;
}
.
.
.
void testPolygon2()
{
//typedef
typedef boost::polygon::polygon_90_data<int> Polygon90Type;
typedef std::vector<Polygon90Type> Polygon90Set;
typedef boost::polygon::polygon_data<int> PolygonType;
typedef std::vector<PolygonType> PolygonSet;
typedef boost::polygon::point_data<int> PointType;
typedef std::vector<PointType> PointSet;
typedef boost::polygon::polygon_traits<Polygon90Type>::point_type Point;
Polygon90Type polygon_1;
Point pts_1[6] = { Point(0,0), Point(0,10), Point(5,12), Point(10,10), Point(10,0), Point(0,0)};
polygon_1.set(pts_1, pts_1 + 6);
std::cout << "polygon_1 area is " << boost::polygon::area(polygon_1) << std::endl;
std::cout << std::endl << __LINE__ << " :
Polygon90Set polygonSet;
polygonSet.push_back(polygon_1);
//an attempt to see result of bloating with 0
boost::polygon::bloat(polygonSet, 0, 0, 0, 0);
std::cout << "nb polygon bloated " << polygonSet.size() << std::endl;
for (auto polygon : polygonSet)
{
std::cout << std::endl << __LINE__ << "####################################" << std::endl;
displayPolygon(polygon, "2 - after being bloated");
std::cout << "area is " << boost::polygon::area(polygon) << std::endl;
}
}
the area it does not correspond to the polygon created.
the area should be 110 but is displayed as 100?
the vertices should be (0,0), (0,10), (5,12), (10,10), (10,0) but are (0/10), (5/10) ,(5/10), (10/10), (10/0), (0/0). It looks like the point (/5/12) is dismissed and replaced with point (5/10).
What am I doing wrong?
thanks.

How to compose and form the binary literals, for example through the conversion from decimal in C++11 / C++14?

int main() {
int x = 3613;
std::cout << "x= " << x << std::endl;
std::string xBin = std::bitset<16>(x).to_string();
std::cout << xBin << std::endl;
unsigned long xDecimal = std::bitset<16>(xBin).to_ulong();
std::cout << xDecimal << std::endl;
std::cout << std::endl << std::endl;
int b01 = 0b11001;
std::cout << "b01= " << b01 << std::endl;
int b02 = 0b1010;
std::cout << "b02= " << b02 << std::endl;
int b03 = b01 + b02;
std::cout << "int b03 = b01 + b02 = " << b03 << std::endl;
return 0;
}
Output:
x= 3613
0000111000011101
3613
b01= 25
b02= 10
int b03 = b01 + b02 = 35
With binary literals we can do normal arithmetic operations, while with the strings obtained with std::bitset<> this is not possible.
So...the question is: how to "compose" the binary literals, for example through the conversion from decimal to binary as obtained using std::bitset<> ?
Looking forward to your kind help. Marco
You shouldn't operate on bitsets by converting them to string and back - that's missing the point of bitsets... Instead you operate on them by using binary operators: &, |, ^, ... (just like you would on usual integers).
std::cout << std::bitset<3>(4) << " or "
<< std::bitset<3>(2) << " = "
<< (std::bitset<3>(4) | std::bitset<3>(2)) << std::endl;
Prints: 100 or 010 = 110
You can find all operators on wiki: http://en.cppreference.com/w/cpp/utility/bitset

Making text output dynamic using ofstream

I'm trying to create a program that outputs the vin, gallons, miles, and mpg of a car to a text file using ofstream.
outfile << setw(8) << "VIN" << setw(19) << "Miles" << setw(10) << "Gallons" << setw(6) << "MPG" << "\n" << "---------------------------------------------\n" << vin(0) << setw(10) << miles(0) << setw(6) << gallons(0) << setw(11) << fixed << showpoint << setprecision(1) << static_cast<double>(miles(0))/gallons(0)<< "\n" << vin(1) << setw(10) << miles(1) << setw(6) << gallons(1) << setw(11) << static_cast<double>(miles(1))/gallons(1) << "\n" << vin(2) << setw(10) << miles(2) << setw(6) << gallons(2) << setw(11) << static_cast<double>(miles(2))/gallons(2) << "\n" << vin(3) << setw(10) << miles(3) << setw(6) << gallons(3) << setw(11) << static_cast<double>(miles(3))/gallons(3) << "\n" << vin(4) << setw(10) << miles(4) << setw(6) << gallons(4) << setw(11) << static_cast<double>(miles(4))/gallons(4) << endl;
Is there a simpler way to accomplish this without having to repeat for each new row? Thanks.
First thing's first, you should object-orient your code to keep it concise. This means by preference keeping the vin, gallons, miles, and mpg as data members of a class.
struct Car
{
// ...
int vin, gallons, miles, mpg;
};
Then you can implement stream inserters/extractors for input and output. Create and put your Car elements in a std::vector<Car> and iterate through them to read or write them to standard input/output.
Ultimately, the line above should be transformed into:
for (const auto& c : cars)
{
std::cout << c << std::endl;
}

Resources