C++ Review Questions

Pages: 12345... 10
Was it ever proposed to use strings in switch statements ?
It's possible in Java and C# so it shouldn't be a problem for the compiler.
> It's possible in Java and C# so it shouldn't be a problem for the compiler.

As specified now, it would be a problem: case labels are constant expressions evaluated at compile-time.

Anyway, it does not add more expressiveness (more than a cascade of if - else if) to the language.
Further re size_t. Since C++20 there is the stand-alone (not member function) function std::ssize() which returns the number of elements as a signed quantity (32 or 64 bit depending upon compile). This is of type std::ptrdiff_t (and not ssize_t as might have been expected - Don't ask...).

Also note that there is also the std::size() stand-alone function that returns the number of elements as type size_t (unsigned).

If you don't fancy mixing signed/unsigned in an expression, then you can use std::ssize() to get a signed value.

Also note that std::size()/std::ssize() can be used to obtain the number of elements in a c-style array where the array has NOT degraded to a pointer. They won't work on a pointer.
Thanks for the responses, you guys always have a plethora of info & insight. The -1 conversion to unsigned integer is disturbing, at this stage I wouldn't have been able to catch it immediately. I now go to the console with trepidation, so many pitfalls and I already know there are dozens more waiting for us.

Would love to learn Win API also some day...but those Win naming conventions...

#define are not type safe and you have to use all those (), better to use templates as they are type safe. I was set on using macros for the simplest of things, only because it stands out in code.

#define PI 3.14159265

But, yes I hear you that it is better to use const.

@JLBorges

As specified now, it would be a problem: case labels are constant expressions evaluated at compile-time.


So, should this work?

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
#include <iostream>
using namespace std;

int main()
{
	//int myInt = 1;
	int myInt;
	cout << "Enter num: " << flush;
	cin >> myInt;

	switch (myInt)
	{
	case(1):
		cout << "one";
		break;
	case(2):
		cout << "two";
		break;
	default:
		break;
	}


	return 0;
}

Yes. But you don't need () around the (1) and (2) for the case label.
I mean in general.
1 + 4/2 is a problem & needs ((1) + (4))/(2)
protoseepp wrote:
#define PI 3.14159265

There are quite a number of approximations,

https://en.wikipedia.org/wiki/Approximations_of_%CF%80

One I routinely use yields 7 exact digits:

const double pi { 355.0/113.0 };

C++20 added several mathematical constants in the <numbers> library, std::numbers::pi is one of them.

https://en.cppreference.com/w/cpp/numeric/constants

There is no need for an unsafe type #define to yield a pi approximation in C++ code.

What the number of exact digits is with std::numbers::pi I don't have a clue, so don't ask me! :Þ
Last edited on
There's also M_PI defined in cmath (usually)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// Definitions of useful mathematical constants
//
// Define _USE_MATH_DEFINES before including <math.h> to expose these macro
// definitions for common math constants.  These are placed under an #ifdef
// since these commonly-defined names are not part of the C or C++ standards
#define M_E        2.71828182845904523536   // e
#define M_LOG2E    1.44269504088896340736   // log2(e)
#define M_LOG10E   0.434294481903251827651  // log10(e)
#define M_LN2      0.693147180559945309417  // ln(2)
#define M_LN10     2.30258509299404568402   // ln(10)
#define M_PI       3.14159265358979323846   // pi
#define M_PI_2     1.57079632679489661923   // pi/2
#define M_PI_4     0.785398163397448309616  // pi/4
#define M_1_PI     0.318309886183790671538  // 1/pi
#define M_2_PI     0.636619772367581343076  // 2/pi
#define M_2_SQRTPI 1.12837916709551257390   // 2/sqrt(pi)
#define M_SQRT2    1.41421356237309504880   // sqrt(2)
#define M_SQRT1_2  0.707106781186547524401  // 1/sqrt(2) 


Last edited on
> There's also M_PI defined in cmath (usually)

C++20: better to rely on the standard facility provided in <numbers>
https://en.cppreference.com/w/cpp/header/numbers

http://coliru.stacked-crooked.com/a/d3b2062b4bfc3834
To use M_PI in C++ console mode with Visual Studio 2022 requires two things I prefer not to do in C++ if I can avoid it:

1. Requires #include <math.h> , <cmath> doesn't include the constant.

2. Requires #define _USE_MATH_DEFINES before the <math.h> header. Ugh, not with strictly kosher C++ code.

Now that C++ has the math constant as part of the C++20 stdlib I'll use that if I can remember it. Before C++20 it was const double pi { 355.0/113.0 };.

I've never needed more than 7 digits of accuracy for my slices of PI.
Sorry, using macro for my silly Hello World to find the area & circumference of circle programs...because it is quicker. My book actually mentions M_PI & <cmath>, and I have not even tried it until just now because you guys have mentioned it. Of course it did not work & I had to add that top #define for it to work (no mention of that in book).


1
2
3
4
#define _USE_MATH_DEFINES
#include <iostream>
#include <cmath>
cout << ">>>>>>>>" << M_PI << endl;	//= >>>>>>>>3.14159 



Good to know...works too...
1
2
3
//Need C++20 for this, Proj Properties/General/C++ Language Standard = C++20
#include <numbers>
cout << ">>>>>>>>" << std::numbers::pi << endl;		//= >>>>>>>>3.14159 
Last edited on
Was it ever proposed to use strings in switch statements ?


I don't know what was proposed but you can use something to turn it into a string and switch off that, like SHA. Occasionally handy to do it that way, but you probably lose most of the performance gains over if/else in overhead of forcing it to work. If your strings are really short, 8 letters or less of actual data, you can cast out to an integer type directly as well, but you need both byte orders for your switch statements so 2 integers per string if you want it portable.

I think I have said it before but unless you exploit the fall-through or default case in some meaningful way, its not worth jumping through a lot of hoops here to deal with strings or floating point. If you do need those features, its whatever you think is best ... you can emulate the features with spaghetti conditions or you can smoke and mirrors the data to make it work with switch.
1. Requires #include <math.h> , <cmath> doesn't include the constant.


Yes it does:

1
2
3
4
5
6
7
#define _USE_MATH_DEFINES

#include <cmath>

int main() {
	const double p { M_PI };
}


compiles fine with VS.
thmm wrote:
Was it ever proposed to use strings in switch statements ?
It's possible in Java and C# so it shouldn't be a problem for the compiler.

There has been proposals to extend the capabilities of the switch statement, but what is probably going to be happening is that they leave switch the way it is and instead introduce a new syntax that will be able to handle strings and also do more advanced "pattern matching".

https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2020/p1371r3.pdf

7.2 inspect rather than switch

This proposal introduces a new inspect statement rather than trying to extend the switch statement. [P0095R0] had proposed extending switch and received feedback to “leave switch alone” in Kona 2015.

The following are some of the reasons considered:
– switch allows the case labels to appear anywhere, which hinders the goal of pattern matching in providing structured inspection.
– The fall-through semantics of switch generally results in break being attached to every case, and is known to be error-prone.
– switch is purposely restricted to integrals for guaranteed efficiency. The primary goal of pattern matching in this paper is expressiveness while being at least as efficient as the naively hand-written code.
Last edited on
@seeplus
Yes, it worked, but what I was trying to say is that it did not work without adding
"#define _USE_MATH_DEFINES" at the top, which my book did not mention anything about.

@Peter87

– The fall-through semantics of switch generally results in break being attached to every case, and is known to be error-prone


Error-prone, really? Why, because ppl forget to place the break; at the end of case, or because intrinsically it may not necessarily branch out properly? I would imagine it is the former?

protoseepp wrote:
Error-prone, really? Why, because ppl forget to place the break; at the end of case, or because intrinsically it may not necessarily branch out properly? I would imagine it is the former?

Yes, the former (forgetting the break). Though one could argue that with enough compiler warnings enabled this becomes not much of an issue.
Yes, it worked, but what I was trying to say is that it did not work without adding
"#define _USE_MATH_DEFINES" at the top, which my book did not mention anything about.


The requirement for this has changed between compilers and compiler versions. Some did require it but not any more, some never did and some still require it (like VS). If you add that statement it'll do no harm even if not needed.

C++20: better to rely on the standard facility provided in <numbers>


Absolutely - if you're using a C++20 compiler. The issue, of course, is that the take-up of C++20 isn't yet anywhere near universal.

This, of course, begs the question - When is it OK to start using C++20 specific features in posted code?
Many people (even bwk?) have said that the worst feature of C is that switches don't break automatically before each case label. This code forms some sort of argument in that debate, but I'm not sure whether it's for or against. - Tom Duff on Duff's device http://doc.cat-v.org/bell_labs/duffs_device
Understood.
Just changed my name guys, too many see & pp & plus in other names.
Error-prone, really? Why, because ppl forget to place the break; at the end of case


This is actually quite a common source of code problems - although less now than it was as many compilers now issue a warning re missing-break at end of case statement(s).

If a compiler does issue a warning re code fallthrough when this is actually what is wanted, then from C++17 you can use attribute [[fallthrough]]

See https://en.cppreference.com/w/cpp/language/attributes/fallthrough
Pages: 12345... 10