- A counterintuitive breaking change related to new comparisons - 13 Updates
- 1.0 / 0.0 - 11 Updates
- Problems With Religion and Love Quotes - 1 Update
| Manfred <noname@add.invalid>: Jan 04 12:56AM +0100 On 1/3/2022 11:24 PM, Andrey Tarasevich wrote: > http://coliru.stacked-crooked.com/a/3f8c3e96cd39f596 > In C++17 the user-defined comparison operator is used. In C++20 > conversion to `int` and subsequent comparison of `int`s is used. That's really odd indeed. Are you sure that is is the C++20 standard that mandates this behavior? I wouldn't be surprised if this were a plain bug in the implementation - possibly related with the changes that you mention above - but still a bug. In fact, gcc 11.2 with plain -std=c++20 gives '01': https://www.godbolt.org/z/rEjfehdnY |
| Manfred <noname@add.invalid>: Jan 04 12:59AM +0100 On 1/4/2022 12:56 AM, Manfred wrote: > possibly related with the changes that you mention above - but still a bug. > In fact, gcc 11.2 with plain -std=c++20 gives '01': > https://www.godbolt.org/z/rEjfehdnY scratch that last bit (for some reason godbolt uses diferent comiler selections fro compilation and program output) https://www.godbolt.org/z/be1q7PErE |
| Chris Vine <chris@cvine--nospam--.freeserve.co.uk>: Jan 04 12:23AM On Mon, 3 Jan 2022 14:13:15 -0800 > Before C++20 the conversion to `const char *` is not used and everything > is perfectly defined here. There's no "undefined behavior" of any kind > in C++17 semantics of this code. Ah yes, I misread your code. You are not comparing pointers, you are comparing indeterminate values. I would need to look it up but my recollection is that reading (and so comparing) an uninitialized value also comprises undefined behaviour, unless it is of unsigned char or std::byte type. Here you seem to be comparing an uninitialized int and char (via S:: operator <) type. |
| Andrey Tarasevich <andreytarasevich@hotmail.com>: Jan 03 04:33PM -0800 On 1/3/2022 4:23 PM, Chris Vine wrote: > also comprises undefined behaviour, unless it is of unsigned char or > std::byte type. Here you seem to be comparing an uninitialized int and > char (via S:: operator <) type. No. That is incorrect. All values involved in these comparisons are perfectly initialized. Both `std::pair` objects are initialized with their default constructors, which in turn perform value-initialization of their members. In my example all `std::pair`s fields are guaranteed to be initialized to zero. Nothing indeterminate here. -- Best regards, Andrey Tarasevich . |
| Chris Vine <chris@cvine--nospam--.freeserve.co.uk>: Jan 04 12:39AM On Tue, 4 Jan 2022 00:23:24 +0000 > also comprises undefined behaviour, unless it is of unsigned char or > std::byte type. Here you seem to be comparing an uninitialized int and > char (via S:: operator <) type. Actually I think they should be initialized because of the brace initializer. I don't use C++ very much any more so I may be wrong about that; but if so there is surely something odd about this. It looks like a bug. |
| Andrey Tarasevich <andreytarasevich@hotmail.com>: Jan 03 04:59PM -0800 On 1/3/2022 3:56 PM, Manfred wrote: > Are you sure that is is the C++20 standard that mandates this behavior? > I wouldn't be surprised if this were a plain bug in the implementation - > possibly related with the changes that you mention above - but still a bug. I'm not yet that good with the intricacies of the implicitly generated comparators, but I see the dilemma the compiler is facing here. It is either 1. user-provided measly `<`-only comparison directly on `S`, or 2. implicit conversion that leads from `S` to `int` with strong full-blown `<=>` comparison. The compiler apparently opts for the latter. I can see the attraction of the latter path, but the fact that it quietly defeats a used-defined comparator looks scary. Granted, it doesn't defeat it directly, since `std::pair`s comparator serves as an intermediary, but still... Once we declare the conversion operator as `explicit`, the phenomenon expectedly disappears and C++20 falls back to the "traditional" behavior. -- Best regards, Andrey Tarasevich |
| Chris Vine <chris@cvine--nospam--.freeserve.co.uk>: Jan 04 01:27AM On Mon, 3 Jan 2022 16:59:25 -0800 Andrey Tarasevich <andreytarasevich@hotmail.com> wrote: [snip] > intermediary, but still... > Once we declare the conversion operator as `explicit`, the phenomenon > expectedly disappears and C++20 falls back to the "traditional" behavior. Frankly, this is unacceptable for an industry standard language such as C++. I was disappointed with some of the breaking changes in C++17 (one bizarre outcome of which was that std::uninitialized_copy, and the other std::unitialized_* functions, gave rise to undefined behaviour according to other parts of the same standard), but this one from C++20 to which you refer is I think worse because it causes breaking compiler behaviour in real life. C++ is not my first choice for new projects nowadays, although it still has some uses. |
| "Chris M. Thomasson" <chris.m.thomasson.1@gmail.com>: Jan 03 06:51PM -0800 On 1/3/2022 9:48 AM, Andrey Tarasevich wrote: > use the user-defined `<` and also output `00`. > The above results were obtained with GCC. Clang 10 outputs `00` even in > `-std=c++20` mode, but Clang 11 and later output `01`. Bugger! |
| Juha Nieminen <nospam@thanks.invalid>: Jan 04 08:27AM > constructors, which in turn perform value-initialization of their > members. In my example all `std::pair`s fields are guaranteed to be > initialized to zero. Nothing indeterminate here. Are you sure "default-initialization = zero-initialization" is guaranteed for POD objects? The default initialization of 'char' (as all the other primitive types) is "don't initialize". Is this different if the 'char' is a member of a POD object that has no explicit constructor? |
| wij <wyniijj@gmail.com>: Jan 04 03:53AM -0800 On Tuesday, 4 January 2022 at 01:49:09 UTC+8, Andrey Tarasevich wrote: > -- > Best regards, > Andrey Tarasevich // file t.cpp #include <iostream> struct S { char c; operator const char *() const { return &c; } friend bool operator <(const S& lhs, const S& rhs) { std::cout << 'c' ; return lhs.c < rhs.c; } }; int main() { std::pair<int, S> p1{}, p2{}; std::cout << (p1 < p2) << (p2 < p1) << std::endl; } ---- []$ g++ t.cpp -std=c++20 []$ ./a.out 01 []$ g++ t.cpp -std=c++17 []$ ./a.out c0c0 --- Problem was verified. It looked to me an overloading issue with std::pair. |
| "Alf P. Steinbach" <alf.p.steinbach@gmail.com>: Jan 04 05:24PM +0100 On 4 Jan 2022 09:27, Juha Nieminen wrote: > The default initialization of 'char' (as all the other primitive types) is > "don't initialize". Is this different if the 'char' is a member of a POD > object that has no explicit constructor? Value initialization was about the only new feature in C++03, which was otherwise just Technical Corrigendum 1. It was invented by Andrew Koenig. The point of value initialization was to guarantee initialization of everything, if anything in an object was initialized (e.g., an object with a `std::string` and a `double` should not end up with the `string` initialized and the `double` indeterminate, as it could in C++98). For that purpose value initialization, used by the `std::pair` default constructor, ends up zero-initializing those things not otherwise initialized. - Alf |
| Andrey Tarasevich <andreytarasevich@hotmail.com>: Jan 04 10:26AM -0800 On 1/4/2022 12:27 AM, Juha Nieminen wrote: > The default initialization of 'char' (as all the other primitive types) is > "don't initialize". Is this different if the 'char' is a member of a POD > object that has no explicit constructor? `std::pair` is a not a POD type (if you insist on using outdated terminology). It has a user-provided constructor. In my example the top-level initialization is performed by the default constructor of `std::pair`, which is guaranteed (by specification of `std::pair`) to invoke *value-initialization* of both members. Value-initialization of `char` (and other scalar types) is zero-initialization. Even if `std::pair` were a POD, the explicitly specified `{}` initializer in my example would still trigger value-initialization of the entire `std::pair`, which would in turn lead to value-initialization of both members. -- Best regards, Andrey Tarasevich |
| "Öö Tiib" <ootiib@hot.ee>: Jan 04 02:49PM -0800 On Tuesday, 4 January 2022 at 02:59:43 UTC+2, Andrey Tarasevich wrote: > intermediary, but still... > Once we declare the conversion operator as `explicit`, the phenomenon > expectedly disappears and C++20 falls back to the "traditional" behavior. I so far thought that <=> only breaks the philosophy of not paying for what we don't use (implementation of < is often cheaper than <=>, operator != is almost always cheaper). Thanks for showing that it is far worse. :( That it somehow manages to compose the <=> when you make operator int() explicit is also odd ... I think all the comparison operators of std::pair were removed by C++20 and replaced with alien flying vessel operator. |
| "Öö Tiib" <ootiib@hot.ee>: Jan 03 11:50PM -0800 On Tuesday, 4 January 2022 at 00:15:10 UTC+2, Manfred wrote: > mean different things. > The irony is that this is probably one of those examples where C beats > C++ - good ol' HUGE_VALF or INFINITE would raise no question at all! The std::numeric_limits<float>::infinity() does not raise questions in actual programs either. It is infinity of float, very explicitly. Issues of BM with it are pseudo-issues. Too lot of characters? WTF? Did the hard drive get full? Name some local constant like "beyond_horizon" or something. Next BM needs to output it to json as number and then what? Runs away crying? |
| Juha Nieminen <nospam@thanks.invalid>: Jan 04 07:58AM > { > static int i = 123; > }; As you probably know, 'static' variables declared inside a class aren't actually member variables, but free-floating variables which visibility scope is inside that class (the term "class variable" is often used for these types of variables, in many OO languages, as opposed to "member variable"). The 'static int i;' in the class definition is just a declaration, and it needs to be actually defined, ie. instantiated somewhere, in one (and only one) compilation unit. If you don't instantiate it somewhere the compiler will be unable to decide where to instantiate it and you'll get a linker error because it has only been declared but not instantiated in any compilation unit. C++17 extended the 'inline' functionality, which does that automatically for you (so that you don't have to instantiate the variable by hand), but prior to it you had to do it yourself. I suppose that when C++98 was standardized it was decided that it's better to specify the initial value of that 'static' variable where it's instantiated rather than where it's declared. (I suppose that technically speaking it wouldn't be hard for compilers to look up the initial value from either one, because to instantiate the variable it needs to see the declaration.) Perhaps it was thought that it causes less confusion because if it's initialized in the declaration it may look like it will be initialized to that value every time the class is instantiated (which, of course, is not the case). > in the same way that const members are initialised? I've never seen a good > reason why it must be this way and it makes for messy header files. I don't think const member variables can be initialized in the class definition in C++98. That syntax was only introduced in C++11. |
| Juha Nieminen <nospam@thanks.invalid>: Jan 04 08:34AM > The irony is that this is probably one of those examples where C beats > C++ - good ol' HUGE_VALF or INFINITE would raise no question at all! What is the type of INFINITE? What if you want it as one of the other two floating point types? (Is casting defined in this case?) |
| Muttley@dastardlyhq.com: Jan 04 09:15AM On Mon, 03 Jan 2022 17:40:28 GMT >due to duplicate definitions of the static variable when the class >definition is include by multiple compilation units. Hence the requirement >to declare it in a single compilation unit. C++ hasn't been translated into C for 25 years at least. Keeping this syntatic quirk for so long rather demonstrates the C++ committee are more interested in adding shiny shiny "fun" stuff to the language that they find interesting rather than improving it for normal developers. |
| Muttley@dastardlyhq.com: Jan 04 09:17AM On Tue, 4 Jan 2022 07:58:41 -0000 (UTC) >I suppose that when C++98 was standardized it was decided that it's >better to specify the initial value of that 'static' variable where >it's instantiated rather than where it's declared. (I suppose that I'd love to see their reasoning for that. >technically speaking it wouldn't be hard for compilers to look up It wouldn't be hard at all. >less confusion because if it's initialized in the declaration it may >look like it will be initialized to that value every time the class >is instantiated (which, of course, is not the case). If someone was new to C++ perhaps, otherwise no. >I don't think const member variables can be initialized in the class >definition in C++98. That syntax was only introduced in C++11. Quite possibly. |
| Manfred <noname@add.invalid>: Jan 04 10:42AM +0100 On 1/4/2022 8:50 AM, Öö Tiib wrote: >> C++ - good ol' HUGE_VALF or INFINITE would raise no question at all! > The std::numeric_limits<float>::infinity() does not raise questions > in actual programs either. It is infinity of float, very explicitly. No, I'm talking about these questions about 'static', 'const', 'constexpr' and similar entertainment. In C INFINITE and HUGE_VAL are "constant expressions", and that is it - good for any purpose. |
| Manfred <noname@add.invalid>: Jan 04 10:47AM +0100 On 1/4/2022 9:34 AM, Juha Nieminen wrote: >> C++ - good ol' HUGE_VALF or INFINITE would raise no question at all! > What is the type of INFINITE? What if you want it as one of the other two > floating point types? (Is casting defined in this case?) "The macro INFINITY expands to a constant expression of type float representing positive or unsigned infinity" It can't be any clearer than that. I believe there are automatic conversions to double and long double. Others can confirm and give the exact reference for this part. HUGE_VAL comes in all variants for different types, from float to double to decimal. |
| scott@slp53.sl.home (Scott Lurndal): Jan 04 03:24PM >quirk for so long rather demonstrates the C++ committee are more interested in >adding shiny shiny "fun" stuff to the language that they find interesting >rather than improving it for normal developers. Of course, they did "fix" it - in a backward compatible way - in C++17, right? |
| Muttley@dastardlyhq.com: Jan 04 04:06PM On Tue, 04 Jan 2022 15:24:06 GMT >>adding shiny shiny "fun" stuff to the language that they find interesting >>rather than improving it for normal developers. >Of course, they did "fix" it - in a backward compatible way - in C++17, right? How exactly do you have backwards compatible new syntax? And waiting until 2017 to (sort of) fix a rather basic syntatic fault doesn't exactly suggest they have their finger on the pulse of C++ devs. But we knew that anyway. |
| "Öö Tiib" <ootiib@hot.ee>: Jan 04 10:15AM -0800 On Tuesday, 4 January 2022 at 11:43:12 UTC+2, Manfred wrote: > No, I'm talking about these questions about 'static', 'const', > 'constexpr' and similar entertainment. In C INFINITE and HUGE_VAL are > "constant expressions", and that is it - good for any purpose. Then I'm lost ... std::numeric_limits<float>::infinity() IS constant expression and that is it, good for any purpose. |
| Manfred <noname@invalid.add>: Jan 04 08:49PM +0100 On 1/4/22 7:15 PM, Öö Tiib wrote: >> "constant expressions", and that is it - good for any purpose. > Then I'm lost ... std::numeric_limits<float>::infinity() IS constant expression > and that is it, good for any purpose. I'll try and lend you a compass: Manfred wrote: > static constexpr float inf = std::numeric_limits<float>::infinity(); > } > /* use my::inf wherever you like */ The reason for it was to try and please C++ purists (we're in c.l.c++ after all), and get a compact representation of INF - I can see the issue with using std::numeric_limits<float>::infinity() embedded in some application expression, which serves totally different purposes than inspecting the details of numeric representation of the implementation. So, suppose you want compact, but you don't like <math.h>, the above is an answer - note that obviously you want my::inf to be a constant expression. Also, you want it local (as you say below), and along similar lines I made it 'static', to make it clear - even if 'constexpr' defaults to it. BUT, then people started whirling around the use of 'static' in combination with 'const' and 'constexpr' and all that fuzz - again, good ol' C wouldn't do that - you'd just use INFINITY or one of the HUGE_VAL variants, and be done with it. |
| love problem <lovepro416@gmail.com>: Jan 04 03:55AM -0800 The problems with religion can be a source of confusion, particularly in love quotes. People who are religious might feel that they are incompatible, and their beliefs may not always be compatible with those of their partner. This can cause misunderstandings, which can be frustrating. But, love can override these problems if the relationship is healthy. If you are a member of a particular religion, you can still enjoy the many benefits of relationships based on your faith. The first problem with religion is that it's based on faith. It's an outdated notion that doesn't reflect the world or the human experience. It also assumes that a person's belief system is true. This, of course, is a fallacy. And that's not to say that falling in love with someone who doesn't share your faith is impossible. Regardless of your background, there is no reason why you can't fall in a romantic relationship. Another issue with religion is that it assumes that the other person shares the same religious beliefs. This isn't true. There is no such thing as absolute love. And this is the biggest problem with religion. Most people, including Christians, believe that God is the essence of love. In the New Testament, we find the phrase, "God is love," twice. Thankfully, this expression does not imply a conflict of faith. https://www.love-problem.solutions/baba-ji/ |
| You received this digest because you're subscribed to updates for this group. You can change your settings on the group membership page. To unsubscribe from this group and stop receiving emails from it send an email to comp.lang.c+++unsubscribe@googlegroups.com. |
No comments:
Post a Comment