C++ Questions

Pages: 1... 678910... 12
I was thinking about mentioning <format>, but figured that would jump the gun on the point I was trying to make about not goobering global stream state.

But yeah, you can totally skip the string streams and use the format library directly.


I have, for years, been using variations on this:

1
2
3
4
5
6
7
template <typename...Args>
std::ostream & print( std::ostream & outs, Args...args )
{
    std::ostringstream oss;
    (oss << ... << args);
    return outs << oss.str();
}

Particularly in the construction of exception types, like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//-----------------------------------------------------------------------------------------
// throw error( "You ", profanity, "ed up." );    // Don't be messed up, okay?
//-----------------------------------------------------------------------------------------
struct error : public std::runtime_error
{
    template <typename...Args>
    error( Args...args ) : std::runtime_error( join( args... ) ) { }

private:
    template <typename...Args>
    std::string join( Args...args )
    {
        std::ostringstream ss;
        (void) (ss << ... << args);
        return ss.str();
    }
};

Fun!
Last edited on
I was thinking about mentioning <format>, but figured that would jump the gun on the point I was trying to make about not goobering global stream state.

I did it for ya, m'ok? :Þ

<format>/{fmt} does make transitioning from printf (and <iomanip>) less painful, though the syntax is a bit different than what you'd expect dealing with printf's syntax.

Looking at the documentation for C++23's std::print/println you can output directly to a stream other than standard C stdout using the same formatting syntax from <format>.

https://en.cppreference.com/w/cpp/io/print

I have yet to really play around with sending output to a stream other than stout, busy fixing major boo-boos with some WinAPI code creating apps silently crashing on exit.

File output using <format>/<print> is next on my list to muck around with. Make lots of egregious errors and damage my desk banging my head on it.



Maybe it is (past) time to start new (and separate) topics on individual and specific C++ questions, this catch-all omnibus one is now 8 pages and has traveled from one end of the C++ universe to the other.

Easier to track all the responses in a smaller topic thread when specific C++ questions are asked and answered.

This topic started out as a query on why std::cout does different stuff with C string char arrays vs. other C arrays. Now it has mutated into a discussion of validating input and formatting output.

Trying to make sense of all this verbiage from stem to stern is exceeding NOT the worth of effort. The bloat will only get worse. YMMV.
Last edited on
Quoth the Grey Wolf:
All the best threads unravel to reveal something else.
Last edited on
Pithy. Heh™.
It’s actually more that I find this forum (like most forums) to be sufficiently unstructured that a thread’s title is meaningless. It gets lost in all the other random threads.

Searching for stuff is about useless too.

I’ve even tried to find my own threads before by typing the exact title into Google and not finding it. After some variations (and sometimes days) of searching, I find it... only to discover I was not mistaken about the title the first time.

(These days I keep a little file full of URLs to threads I want to refer to every now and then — not necessarily just my threads.)

Better to just find threads by typing enough keywords into Google to get something that probably talks about what you want to see.


For a short time you could go to your profile and get a list of every post you ever created, but that was part of some ongoing forum update (when we got our new look) and disappeared too soon.
Last edited on
At least with "my topics" you can see what threads/posts one has participated in, not just the thread starters.
Thanks fellas!

seeplus
The code is for a cin keyboard in and cout to display. It is from Murach's C++ Programming 2018 (p159). This book gave a very good explanation of the getline() followed by cin issue that I had posted about earlier in this thread before getting my hands on this book. You fellas are absolutely right about having to read multiple books (and then some) to get a more complete picture, treasured advice!

Here is the code, I only changed the string literals to cout:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
//Chap 5: p159
//The Invoice 3.0 program
#include<iostream>
#include<iomanip>

using namespace std;

int main()
{
	char customer_type;
	while (true)
	{
		cout << "Enter customer type (r/w):";
		cin >> customer_type;
		cin.ignore(numeric_limits<streamsize>::max(), '\n');
		if (tolower(customer_type) == 'r' || tolower(customer_type) == 'w')
			break;
		else
			cout << "Invalid customer entry! Try again.\n";
	}

	double subtotal;
	while (true)
	{
		cout << "Enter subtotal:";
		cin >> subtotal;

		if (cin.good())
			break;
		else if (cin.fail())
		{
			cout << "Invalid number! Try again.\n";
			cin.clear();
			cin.ignore(numeric_limits<streamsize>::max(), '\n');
		}
		else if (cin.bad())
		{
			cout << "BAD STREAM...EXITING PROGRAM....GOODBYE!!!\n";
			return 0;
		}
	}
	
	double discount_percent;
	if (tolower(customer_type) == 'r')
	{
		if (subtotal < 100)
			discount_percent = .0;
		else if (subtotal >= 100 && subtotal < 250)
			discount_percent = .1;
		else
			discount_percent = .2;
	}
	else if (tolower(customer_type) == 'w')
	{
		if (subtotal < 500)
			discount_percent = .4;
		else
			discount_percent = .5;
	}
	else
		discount_percent = .0;

	double discount_amount = subtotal * discount_percent;
	double invoice_total = subtotal - discount_amount;

	int col1 = 18;
	int col2 = 8;

	cout << fixed << setprecision(2) << endl		//2 decimal places
		<< "INVOICE" << endl
		<< left << setw(col1) << "Subtotal:"
		<< right << setw(col2) << subtotal << endl
		<< left << setw(col1) << "Discount Percent:"
		<< right << setw(col2) << discount_percent << endl
		<< left << setw(col1) << "Discount Amount:"
		<< right << setw(col2) << discount_amount << endl
		<< left << setw(col1) << "Invoice total:"
		<< right << setw(col2) << invoice_total << endl;
}


I did not realize .fail bit will go high when the .bad bit does too. That is the exact order in the book & they had another example stating that the eof() bit must be checked before the fail() bit, because the former will set the latter and they showed proper order in the code example for this.

Gotcha now fellas on physical vs logical errors and a bad() bit being more serious on the physical level. It may require to terminate the program IF it makes no sense to continue.
Duthomhas
Once again thanks and it all makes sense!

Yes, stringstreams are invaluable. I can only imagine what you guys had to go through before stringstreams to do something so effortless now, search a line and make sure there were no other chars/special chars and only numbers, look for the "." period....to get your double/float. What, the data is in scientific notation...more checking.

You rant because you care about the craft. But imagine what a set of books that covers C++ extensively will look like, it would look more like an encyclopedia set and that is before you even get into all the various libraries and methods/methodologies of coding a certain outcome. Some programmers are too busy with the workload too and may not be overly concerned with the minutia...make it happen and move on...and get me there quick via reference in the beginning.

George
I read the initial <format> chapt in that beginning book you recommended and I need to reread it and actually practice the format samples. Good book too, but what I dislike is the smaller print, which has kept my abstinence. I use physical books to get away from the computer.

Perhaps it is time to move on, although asking questions the way I have been asking will produce tons of posts from me. Will make it seem like I am hogging the site...it was fun and insightful while it lasted.

Super thanks to you guys!
Eh, for the grand finale...sample at the end of the chapt.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
//Chap 5: p179
//The Temperature Analyzer Program

#include<iostream>
#include<fstream>
#include<string>
#include<iomanip>
#include<sstream>
using namespace std;

int main()
{
	cout << "Temperature Analyzer\n\n";

	string filename;
	ifstream infile;

	while (true)
	{
		cout << "Enter input filename : ";
		cin >> filename;
		cin.ignore(numeric_limits<streamsize>::max(), '\n');

		infile.open(filename);
		if (infile)
		{
			break;
		}
		cout << "Unable to open input file \"" << filename << "\", try again!\n";
	}
	cout << "Input file \"" << filename << "\" opened successfully.\n\n";

	cout << fixed << setprecision(1);

	int col = 7;	//col width
	cout	<< setw(col) << "Low" << setw(col) << "High"
			<< setw(col) << "Avg" << endl;
	cout << "----------------------------------------------" << endl;

	double low = 0.0;
	double high = 0.0;
	double avg = 0.0;
	double avg_total = 0.0;
	double lowest = 1000.0;
	double highest = - 1000.0;
	int lines_read = 0;
	int lines_processed = 0;

	string line;
	stringstream ss;
	while (getline(infile, line))
	{
		++lines_read;
		ss.str(line);
		ss.clear();

		if (ss >> low >> high)
		{
			++lines_processed;

			avg = (low + high) / 2;

			cout	<< setw(col) << low << setw(col) << high 
					<< setw(col) << avg << endl;

			avg_total += avg;
			if (low < lowest)
				lowest = low;
			if (high > highest)
				highest = high;
		}
	}
	infile.close();

	cout	<< endl
			<< lines_processed << " of "
			<< lines_read << " lines successfully processed.\n\n";

	double avg_daily = avg_total / lines_processed;
	
	int coll = 17;
	int col2 = 7;
	cout	<< left << setw(coll) << "Lowest temp: "
			<< right << setw(col2) << lowest << endl
			<< left  << setw(coll) << "Highest temp: "
			<< right << setw(col2) << highest << endl 
			<< left << setw(coll) << "Avg daily temp: "
			<< right << setw(col2) << avg_daily << endl << endl;
}
/*
OUTPUT:
Temperature Analyzer

Enter input filename : badName
Unable to open input file "badName", try again!
Enter input filename : temps.txt
Input file "temps.txt" opened successfully.

	Low   High    Avg
----------------------------------------------
   48.4   57.2   52.8
   46.0   50.0   48.0
   45.0   55.3   50.1
   54.0   61.0   57.5
   37.0   52.0   44.5
   37.0   43.3   40.1
   45.0   57.0   51.0
   48.0   55.0   51.5
   54.0   57.0   55.5
   48.1   54.3   51.2

10 of 14 lines successfully processed.

Lowest temp:        37.0
Highest temp:       61.0
Avg daily temp:     50.2
*/


/*
temps.txt
48.372	57.23
46	50
45.01	55.273839404
54	61
37	52
37	43.27
45	57
n/a	64
55.34	n/a
50a	59
48.0	55.0
54	57
48.1	54.27
*/
I did not realize .fail bit will go high when the .bad bit does too


The .fail and .bad bits are independent of each other. The issue is that .fail() (function) checks both .fail and .bad bits and returns true if either are set. .bad() (function) just tests the .bad bit.
re sample code. Not withstanding previous comments:

A file name can contain a space char. So L21 isn't correct. It should use getline().

L44-45. The logic is correct (setting lowest to high and highest to low) but usually you'd use the min/max number for the type used. ie:

1
2
double lowest = std::numeric_limits<double>::max();
double highest = std::numeric_limits<double>::lowest();


See https://cplusplus.com/reference/limits/numeric_limits/
Last edited on
Thanks.

I did understand that, go high as in the or gate goes high there.
fail (fail || bad)
bad (bad)

I would change some things too, but that was directly from the book. I am sure some things were done to make the lesson easier to digest.
seeplus wrote:
L44-45. The logic is correct (setting lowest to high and highest to low) but usually you'd use the min/max number for the type used. ie:
1
2
double lowest = std::numeric_limits<double>::max();
double highest = std::numeric_limits<double>::min();

Note that for floating-point types min() returns a very small positive value. You probably want to use lowest() instead.

 
double highest = std::numeric_limits<double>::lowest();
Last edited on
Whoops, my bad - yes you're right! I've changed the code.
Last edited on
Looking at the documentation for C++23's std::print/println


What were the standard committee members smoking when they agreed that if a file argument is specified it is of type FILE* ??????? That is soooo c. It's ostream in C++. The cppreference.com example uses the c functions fopen() and fclose(). I thought we'd put all that behind us in C++
It seems to be overloaded for both FILE* and std::ostream&

https://en.cppreference.com/w/cpp/io/print <-- FILE*
https://en.cppreference.com/w/cpp/io/basic_ostream/print <-- std::ostream&
Last edited on
Hey, @SubZeroWins, the BB-code for the forum gives you a couple of interesting formatting options.

For the results of running code, you can put it in its own [output] block:

[code]
#include <iostream>
int main()
{
  std::cout << "Hello world!\n";
}
[/code]
[output]Hello world![/output]


1
2
3
4
5
#include <iostream>
int main()
{
  std::cout << "Hello world!\n";
}

Hello world!


The other option is to separate code and output by a few dashes - (minimum of three, iirc):

[code]
#include <iostream>
int main()
{
  std::cout << "Hello world!\n";
}
-----
Hello world!
[/code]


1
2
3
4
5
#include <iostream>
int main()
{
  std::cout << "Hello world!\n";
}
Hello world!


Neat, huh?
Last edited on
A refresher (and very old) CPlusPlus article for how to use BB tags:

https://cplusplus.com/articles/z13hAqkS/

Yes, it is 3 --- to display code and output when enclosed in code tags. :Þ

If you've already posted something you want reformatted with code tags:

https://cplusplus.com/articles/jEywvCM9/

Another way to "show" the output of a properly compilable bit of code thrown up here is to compile and run the code with an online compiler, Coliru Viewer is one such option.

1
2
3
4
5
6
7
8
9
10
11
12
#include "iostream"

template <typename T, typename U>
auto max( T x, U y )
{
   return (x > y) ? x : y;
}

int main( )
{
   std::cout << max( 6.5, 5 ) << '\n';
}

http://coliru.stacked-crooked.com/a/49684f74d31a7611

Lately I've been pasting the link to Coliru when I throw up some code so someone can edit the code, make modifications if they want and retest the code. Without having to fire up their installed compiler if they have one.

Coliru doesn't support all C++20/C++23 features yet, it uses GCC 13.1.0. :(
Last edited on
Clicking on the “Edit & run on cpp.sh” button takes you to the cplusplus.com online compiler, which AFAICT is just GCC with the latest options. It is a little more limited than some of the more impressive online compilers, but it compares very well given some other OLC’s I’ve encountered, and you don’t have to do anything besides making sure your [code] block contains a full program (with a main() function and all).
Pages: 1... 678910... 12