Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.c++ > #85937 > unrolled thread

`bool` in pointer arithmetic: when does the promotion occur, if ever?

Started byAndrey Tarasevich <andreytarasevich@hotmail.com>
First post2022-08-15 10:45 -0700
Last post2022-08-17 09:08 -0700
Articles 16 — 7 participants

Back to article view | Back to comp.lang.c++


Contents

  `bool` in pointer arithmetic: when does the promotion occur, if ever? Andrey Tarasevich <andreytarasevich@hotmail.com> - 2022-08-15 10:45 -0700
    Re: `bool` in pointer arithmetic: when does the promotion occur, if ever? David Brown <david.brown@hesbynett.no> - 2022-08-15 20:09 +0200
      Re: `bool` in pointer arithmetic: when does the promotion occur, if ever? Andrey Tarasevich <andreytarasevich@hotmail.com> - 2022-08-15 11:29 -0700
        Re: `bool` in pointer arithmetic: when does the promotion occur, if ever? Andrey Tarasevich <andreytarasevich@hotmail.com> - 2022-08-15 11:35 -0700
        Re: `bool` in pointer arithmetic: when does the promotion occur, if ever? David Brown <david.brown@hesbynett.no> - 2022-08-15 21:20 +0200
          Re: `bool` in pointer arithmetic: when does the promotion occur, if ever? red floyd <no.spam.here@its.invalid> - 2022-08-15 13:49 -0700
          Re: `bool` in pointer arithmetic: when does the promotion occur, if ever? Andrey Tarasevich <andreytarasevich@hotmail.com> - 2022-08-15 13:59 -0700
            Re: `bool` in pointer arithmetic: when does the promotion occur, if ever? David Brown <david.brown@hesbynett.no> - 2022-08-16 09:12 +0200
              Re: `bool` in pointer arithmetic: when does the promotion occur, if ever? Andrey Tarasevich <andreytarasevich@hotmail.com> - 2022-08-16 09:56 -0700
                Re: `bool` in pointer arithmetic: when does the promotion occur, if ever? Tim Rentsch <tr.17687@z991.linuxsc.com> - 2022-09-15 07:18 -0700
                  Re: `bool` in pointer arithmetic: when does the promotion occur, if ever? Language Lawyer <language.lawyer@gmail.com> - 2022-09-19 03:28 -0700
                    Re: `bool` in pointer arithmetic: when does the promotion occur, if ever? Tim Rentsch <tr.17687@z991.linuxsc.com> - 2022-10-02 12:37 -0700
    Re: `bool` in pointer arithmetic: when does the promotion occur, if ever? Tim Rentsch <tr.17687@z991.linuxsc.com> - 2022-08-15 14:36 -0700
      Re: `bool` in pointer arithmetic: when does the promotion occur, if ever? Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2022-08-15 14:57 -0700
    Re: `bool` in pointer arithmetic: when does the promotion occur, if ever? "Alf P. Steinbach" <alf.p.steinbach@gmail.com> - 2022-08-16 21:13 +0200
    Re: `bool` in pointer arithmetic: when does the promotion occur, if ever? Language Lawyer <language.lawyer@gmail.com> - 2022-08-17 09:08 -0700

#85937 — `bool` in pointer arithmetic: when does the promotion occur, if ever?

FromAndrey Tarasevich <andreytarasevich@hotmail.com>
Date2022-08-15 10:45 -0700
Subject`bool` in pointer arithmetic: when does the promotion occur, if ever?
Message-ID<tde0o3$3nqef$1@dont-email.me>
Hello

Sound like a silly question (and it might just as well be), but 
nevertheless:

    int *a = <whatever>;
    bool b = true;
    a + b;

How does the binary `+` work in this case? Its operands are an `int *` 
and a `bool`. `bool` is an integer type, so the requirements are met and 
the expression is valid. Naturally we expect that `bool` to be promoted 
to an integer value of 1, and the rest is clear.

But where does it say in the standard that `bool` should get promoted in 
this context? There is no global rule requiring an unconditional 
promotion, i.e. each operator's specification mandates integral 
promotions individually and explicitly. And I don't see integral 
promotions mentioned anywhere in [expr.add].

It does mention usual arithmetic conversions (UAC), of course, and UAC 
include integral promotions. But UAC are only applicable when _both_ 
operands have enumeration or arithmetic type. UAC are not applied when 
one operand is a pointer. (The definition of UAC does not accommodate 
for such possibility.)

So, how does pointer+bool addition work then? When does `true` turn into 
1 here?

-- 
Best regards
Andrey

[toc] | [next] | [standalone]


#85938

FromDavid Brown <david.brown@hesbynett.no>
Date2022-08-15 20:09 +0200
Message-ID<tde24g$3o0ua$1@dont-email.me>
In reply to#85937
On 15/08/2022 19:45, Andrey Tarasevich wrote:
> Hello
> 
> Sound like a silly question (and it might just as well be), but 
> nevertheless:
> 
>     int *a = <whatever>;
>     bool b = true;
>     a + b;
> 
> How does the binary `+` work in this case? Its operands are an `int *` 
> and a `bool`. `bool` is an integer type, so the requirements are met and 
> the expression is valid. Naturally we expect that `bool` to be promoted 
> to an integer value of 1, and the rest is clear.

Yes.

> 
> But where does it say in the standard that `bool` should get promoted in 
> this context? There is no global rule requiring an unconditional 
> promotion, i.e. each operator's specification mandates integral 
> promotions individually and explicitly. And I don't see integral 
> promotions mentioned anywhere in [expr.add].
> 

My numbering here is from C++20 draft N4860.  I don't think anything 
relevant has changed in different standards, but of course section 
numbers might.

"7.3.6 Integral promotions" says that a "prvalue of type bool can be 
converted to a prvalue of type int".  This is one of the "integral 
promotions".

"7.4 Usual arithmetic conversions" says that integral promotions are 
performed on both operands of many binary operators, if they are not 
trumped by floating point conversions.  There is a footnote saying "As a 
consequence, operands of type bool, char8_t, char16_t, char32_t, 
wchar_t, or an enumerated type are converted to some integral type."


> It does mention usual arithmetic conversions (UAC), of course, and UAC 
> include integral promotions. But UAC are only applicable when _both_ 
> operands have enumeration or arithmetic type. UAC are not applied when 
> one operand is a pointer. (The definition of UAC does not accommodate 
> for such possibility.)
> 
> So, how does pointer+bool addition work then? When does `true` turn into 
> 1 here?
> 

Under "7.6.6 Additive operators", it says that the usual arithmetic 
conversions are performed on operands of arithmetic or enumeration type 
- that includes bool.

[toc] | [prev] | [next] | [standalone]


#85940

FromAndrey Tarasevich <andreytarasevich@hotmail.com>
Date2022-08-15 11:29 -0700
Message-ID<tde3ab$3o7iu$1@dont-email.me>
In reply to#85938
On 8/15/2022 11:09 AM, David Brown wrote:
>>
>> So, how does pointer+bool addition work then? When does `true` turn 
>> into 1 here?
>>
> 
> Under "7.6.6 Additive operators", it says that the usual arithmetic 
> conversions are performed on operands of arithmetic or enumeration type 
> - that includes bool.

No, no, no... You can't just arbitrarily pluck this part out of the 
whole rule. After/if you apply usual arithmetic conversions here, you 
are required to continue to follow the spec and complete all steps. You 
are required to follow the "Then the following rules are applied to the 
promoted operands:" part in 7.4/1.3 
(http://eel.is/c++draft/expr.arith.conv#1.3) The specification of usual 
arithmetic conversions does not have an "early exit" clause if one 
operand is a pointer.

Now, once you start following these "following rules", it becomes clear 
that they are not applicable (or defective) if one operand is a pointer. 
Firstly, the concept of "[integer conversion] rank" is not applicable to 
pointer types. Secondly, (if we ignore the "firstly") these rules 
ultimately require us to convert both operands to a common integer type.

Obviously, in pointer+bool contexts operands are NOT converted to a 
common integer type. So, no, usual arithmetic conversions do not apply 
here. As I already stated, the intent of the standard wording is to say 
that usual arithmetic conversions apply only when _both_ operands have 
integral or enum type.

-- 
Best regards,
Andrey

[toc] | [prev] | [next] | [standalone]


#85941

FromAndrey Tarasevich <andreytarasevich@hotmail.com>
Date2022-08-15 11:35 -0700
Message-ID<tde3lq$3oaov$1@dont-email.me>
In reply to#85940
On 8/15/2022 11:29 AM, Andrey Tarasevich wrote:
> On 8/15/2022 11:09 AM, David Brown wrote:
> Secondly, (if we ignore the "firstly") these rules 
> ultimately require us to convert both operands to a common integer type.
> 
> Obviously, in pointer+bool contexts operands are NOT converted to a 
> common integer type. So, no, usual arithmetic conversions do not apply 
> here. As I already stated, the intent of the standard wording is to say 
> that usual arithmetic conversions apply only when _both_ operands have 
> integral or enum type.

... when both operands have *arithmetic* or enum type.

-- 
Best regards,
Andrey

[toc] | [prev] | [next] | [standalone]


#85944

FromDavid Brown <david.brown@hesbynett.no>
Date2022-08-15 21:20 +0200
Message-ID<tde69i$3oucq$1@dont-email.me>
In reply to#85940
On 15/08/2022 20:29, Andrey Tarasevich wrote:
> On 8/15/2022 11:09 AM, David Brown wrote:
>>>
>>> So, how does pointer+bool addition work then? When does `true` turn 
>>> into 1 here?
>>>
>>
>> Under "7.6.6 Additive operators", it says that the usual arithmetic 
>> conversions are performed on operands of arithmetic or enumeration 
>> type - that includes bool.
> 
> No, no, no... You can't just arbitrarily pluck this part out of the 
> whole rule. After/if you apply usual arithmetic conversions here, you 
> are required to continue to follow the spec and complete all steps. You 
> are required to follow the "Then the following rules are applied to the 
> promoted operands:" part in 7.4/1.3 
> (http://eel.is/c++draft/expr.arith.conv#1.3) The specification of usual 
> arithmetic conversions does not have an "early exit" clause if one 
> operand is a pointer.
> 
> Now, once you start following these "following rules", it becomes clear 
> that they are not applicable (or defective) if one operand is a pointer. 
> Firstly, the concept of "[integer conversion] rank" is not applicable to 
> pointer types. Secondly, (if we ignore the "firstly") these rules 
> ultimately require us to convert both operands to a common integer type.
> 
> Obviously, in pointer+bool contexts operands are NOT converted to a 
> common integer type. So, no, usual arithmetic conversions do not apply 
> here. As I already stated, the intent of the standard wording is to say 
> that usual arithmetic conversions apply only when _both_ operands have 
> integral or enum type.
> 

Read the paragraphs in the standards, and follow the rules.  When you 
write "p + b", with "p" being a pointer-to-int and "b" being a bool, you 
get the following chain:

"7.6.6 Additive operators" says "The usual arithmetic conversions (7.4) 
are performed for operands of arithmetic or enumeration type."  The 
pointer is not an arithmetic or enumeration type, but the boolean is.

The "7.4 Usual arithmetic conversions" are primarily concerned about two 
operands, but the pattern-matching list of "Otherwise, if either operand 
is ..." can be applied to a single operand too.  Since there are no 
floats, we hit "the integral promotions shall be performed on both 
operands" - in this case, just the one.  None of the rules after that 
are triggered.

(Perhaps the "usual arithmetic conversions" are actually applied to both 
operands.  A pointer would return unscathed by "integral promotions" as 
it matches none of the rule triggers there.)

[toc] | [prev] | [next] | [standalone]


#85947

Fromred floyd <no.spam.here@its.invalid>
Date2022-08-15 13:49 -0700
Message-ID<tdebh2$3pvpl$1@redfloyd.dont-email.me>
In reply to#85944
On 8/15/2022 12:20 PM, David Brown wrote:
> On 15/08/2022 20:29, Andrey Tarasevich wrote:
>> On 8/15/2022 11:09 AM, David Brown wrote:
>>>>
>>>> So, how does pointer+bool addition work then? When does `true` turn 
>>>> into 1 here?
>>>>
>>>
>>> Under "7.6.6 Additive operators", it says that the usual arithmetic 
>>> conversions are performed on operands of arithmetic or enumeration 
>>> type - that includes bool.
>>
>> No, no, no... You can't just arbitrarily pluck this part out of the 
>> whole rule. After/if you apply usual arithmetic conversions here, you 
>> are required to continue to follow the spec and complete all steps. 
>> You are required to follow the "Then the following rules are applied 
>> to the promoted operands:" part in 7.4/1.3 
>> (http://eel.is/c++draft/expr.arith.conv#1.3) The specification of 
>> usual arithmetic conversions does not have an "early exit" clause if 
>> one operand is a pointer.
>>
>> Now, once you start following these "following rules", it becomes 
>> clear that they are not applicable (or defective) if one operand is a 
>> pointer. Firstly, the concept of "[integer conversion] rank" is not 
>> applicable to pointer types. Secondly, (if we ignore the "firstly") 
>> these rules ultimately require us to convert both operands to a common 
>> integer type.
>>
>> Obviously, in pointer+bool contexts operands are NOT converted to a 
>> common integer type. So, no, usual arithmetic conversions do not apply 
>> here. As I already stated, the intent of the standard wording is to 
>> say that usual arithmetic conversions apply only when _both_ operands 
>> have integral or enum type.
>>
> 
> Read the paragraphs in the standards, and follow the rules.  When you 
> write "p + b", with "p" being a pointer-to-int and "b" being a bool, you 
> get the following chain:
> 
> "7.6.6 Additive operators" says "The usual arithmetic conversions (7.4) 
> are performed for operands of arithmetic or enumeration type."  The 
> pointer is not an arithmetic or enumeration type, but the boolean is.
> 
> The "7.4 Usual arithmetic conversions" are primarily concerned about two 
> operands, but the pattern-matching list of "Otherwise, if either operand 
> is ..." can be applied to a single operand too.  Since there are no 
> floats, we hit "the integral promotions shall be performed on both 
> operands" - in this case, just the one.  None of the rules after that 
> are triggered.
> 
> (Perhaps the "usual arithmetic conversions" are actually applied to both 
> operands.  A pointer would return unscathed by "integral promotions" as 
> it matches none of the rule triggers there.)

Given the potential ambiguity in standard conformant behavior, it's
probably better to make it explicit...

[going back to Andrey's initial post]

    int *a = <whatever>;
    bool b = true;
    a + static_cast<int>(b);

[toc] | [prev] | [next] | [standalone]


#85949

FromAndrey Tarasevich <andreytarasevich@hotmail.com>
Date2022-08-15 13:59 -0700
Message-ID<tdec2o$3q32d$1@dont-email.me>
In reply to#85944
On 8/15/2022 12:20 PM, David Brown wrote:
>>
>> Obviously, in pointer+bool contexts operands are NOT converted to a 
>> common integer type. So, no, usual arithmetic conversions do not apply 
>> here. As I already stated, the intent of the standard wording is to 
>> say that usual arithmetic conversions apply only when _both_ operands 
>> have integral or enum type.
>>
> 
> Read the paragraphs in the standards, and follow the rules.  When you 
> write "p + b", with "p" being a pointer-to-int and "b" being a bool, you 
> get the following chain:

That's exactly what I'm doing.

> "7.6.6 Additive operators" says "The usual arithmetic conversions (7.4) 
> are performed for operands of arithmetic or enumeration type."  The 
> pointer is not an arithmetic or enumeration type, but the boolean is.
> 
> The "7.4 Usual arithmetic conversions" are primarily concerned about two 
> operands, but the pattern-matching list of "Otherwise, if either operand 
> is ..." can be applied to a single operand too.  

That does not mean that you can simply pluck that part out of the whole 
rule and nonchalantly discard the rest. (And I feel like I'm repeating 
myself.)

> Since there are no 
> floats, we hit "the integral promotions shall be performed on both 
> operands" - in this case, just the one.  None of the rules after that 
> are triggered.

That's not true. And I already covered this above.

Firstly, the "rules after that" attempt to apply the concept of integer 
conversion rank to both operands, which is not defined for pointer 
types. The C++ standard does not adhere to the principle that "if some 
rule is stated nonsensically then it is simply not triggered". Such 
rules would be hard defects.

Secondly, in any case these rules cannot be brushed off under "not 
triggered" premise because the very last rule in the list is a "sink": 
it is not protected by a trigger at all, it is unconditional. If none of 
the previous rules are "triggered" then the last rule applies:

   http://eel.is/c++draft/expr.arith.conv#1.3.5
   - Otherwise, both operands are converted to the unsigned integer type 
corresponding to the type of the operand with signed integer type.

What do you expect this to do if one operand is a pointer?

I thought that this problem would be obvious, but apparently I need to 
spell out every detail... So, it is is actually me who's telling you to 
"read the paragraphs in the standards, and follow the rules".

> (Perhaps the "usual arithmetic conversions" are actually applied to both 
> operands.  A pointer would return unscathed by "integral promotions" as 
> it matches none of the rule triggers there.)

Yes, integral promotions are safe specifically because of this: every 
rule in integral promotions is protected by an "if barrier" and 
therefore it leaves pointers unchanged (assuming a pointer can get there 
legally).

But the question is not about integral promotions. The question is about 
usual arithmetic conversions. Rules of usual arithmetic conversions do 
not implement this kind of protection.

-- 
Best regards,
Andrey

[toc] | [prev] | [next] | [standalone]


#85954

FromDavid Brown <david.brown@hesbynett.no>
Date2022-08-16 09:12 +0200
Message-ID<tdfg0k$dbm$1@dont-email.me>
In reply to#85949
On 15/08/2022 22:59, Andrey Tarasevich wrote:
> On 8/15/2022 12:20 PM, David Brown wrote:
>>>
>>> Obviously, in pointer+bool contexts operands are NOT converted to a 
>>> common integer type. So, no, usual arithmetic conversions do not 
>>> apply here. As I already stated, the intent of the standard wording 
>>> is to say that usual arithmetic conversions apply only when _both_ 
>>> operands have integral or enum type.
>>>
>>
>> Read the paragraphs in the standards, and follow the rules.  When you 
>> write "p + b", with "p" being a pointer-to-int and "b" being a bool, 
>> you get the following chain:
> 
> That's exactly what I'm doing.
> 
>> "7.6.6 Additive operators" says "The usual arithmetic conversions 
>> (7.4) are performed for operands of arithmetic or enumeration type."  
>> The pointer is not an arithmetic or enumeration type, but the boolean is.
>>
>> The "7.4 Usual arithmetic conversions" are primarily concerned about 
>> two operands, but the pattern-matching list of "Otherwise, if either 
>> operand is ..." can be applied to a single operand too. 
> 
> That does not mean that you can simply pluck that part out of the whole 
> rule and nonchalantly discard the rest. (And I feel like I'm repeating 
> myself.)

Yes, you /can/.  These sections are written as lists of "otherwise, if 
..." rules.  Once you've triggered such a rule, the others on the list 
/can/ be discarded.  If none are triggered, then nothing happens - no 
promotions or conversions apply, nor is the code explicitly ruled valid 
or invalid.

> 
>> Since there are no floats, we hit "the integral promotions shall be 
>> performed on both operands" - in this case, just the one.  None of the 
>> rules after that are triggered.
> 
> That's not true. And I already covered this above.

I agree that "in pointer+bool contexts operands are NOT converted to a 
common integer type".  But I disagree that this means the paragraphs 
about "usual arithmetic conversions" and "integral promotions" don't 
apply - the standards explicitly say they do.

> 
> Firstly, the "rules after that" attempt to apply the concept of integer 
> conversion rank to both operands, which is not defined for pointer 
> types. The C++ standard does not adhere to the principle that "if some 
> rule is stated nonsensically then it is simply not triggered". Such 
> rules would be hard defects.

SFINAE ?

I think the way it is written /is/ defective - it is not clear enough 
how these rules apply.  I am merely trying to explain how /I/ interpret 
them.  My interpretation gives almost certainly the same results as the 
C++ committee intended, and it matches both the C standards (which are 
clearer here) and implementations.  But that does not mean it is correct 
- there may be other explanations that give the same resulting 
behaviour, and it may be that the standard is defective and there are no 
consistent readings of the standard here.


> 
> Secondly, in any case these rules cannot be brushed off under "not 
> triggered" premise because the very last rule in the list is a "sink": 
> it is not protected by a trigger at all, it is unconditional. If none of 
> the previous rules are "triggered" then the last rule applies:
> 
>    http://eel.is/c++draft/expr.arith.conv#1.3.5
>    - Otherwise, both operands are converted to the unsigned integer type 
> corresponding to the type of the operand with signed integer type.
> 
> What do you expect this to do if one operand is a pointer?

It doesn't get that far.  As I interpret this, only the bool gets the 
"usual arithmetic conversions" - thus references to "both operands" only 
apply to the single operand.  After the integral promotions are 
performed (turning the bool into int), we get "If both operands have the 
same type, no further conversion is needed" and stop there.

> 
> I thought that this problem would be obvious, but apparently I need to 
> spell out every detail... So, it is is actually me who's telling you to 
> "read the paragraphs in the standards, and follow the rules".

I'm sorry - I thought it was /you/ who asked the original question, 
looking for help?  And the thanks I get for going through the paragraphs 
and explaining as best I can how I read the standards, is to get my head 
bitten off?

Maybe my understanding of the standards is not quite right.  Maybe my 
explanation wasn't great.  But if this is your idea of how to say "I 
don't see it that way, but thanks for trying", I'll leave you to figure 
things out some other way.  Perhaps someone else will reply to you, and 
maybe give you a reading that you'd prefer.

> 
>> (Perhaps the "usual arithmetic conversions" are actually applied to 
>> both operands.  A pointer would return unscathed by "integral 
>> promotions" as it matches none of the rule triggers there.)
> 
> Yes, integral promotions are safe specifically because of this: every 
> rule in integral promotions is protected by an "if barrier" and 
> therefore it leaves pointers unchanged (assuming a pointer can get there 
> legally).
> 
> But the question is not about integral promotions. The question is about 
> usual arithmetic conversions. Rules of usual arithmetic conversions do 
> not implement this kind of protection.
> 

[toc] | [prev] | [next] | [standalone]


#85955

FromAndrey Tarasevich <andreytarasevich@hotmail.com>
Date2022-08-16 09:56 -0700
Message-ID<tdgi76$3p1q$1@dont-email.me>
In reply to#85954
On 8/16/2022 12:12 AM, David Brown wrote:
>>
>> Secondly, in any case these rules cannot be brushed off under "not 
>> triggered" premise because the very last rule in the list is a "sink": 
>> it is not protected by a trigger at all, it is unconditional. If none 
>> of the previous rules are "triggered" then the last rule applies:
>>
>>    http://eel.is/c++draft/expr.arith.conv#1.3.5
>>    - Otherwise, both operands are converted to the unsigned integer 
>> type corresponding to the type of the operand with signed integer type.
>>
>> What do you expect this to do if one operand is a pointer?
> 
> It doesn't get that far.  As I interpret this, only the bool gets the 
> "usual arithmetic conversions" - thus references to "both operands" only 
> apply to the single operand.  After the integral promotions are 
> performed (turning the bool into int), we get "If both operands have the 
> same type, no further conversion is needed" and stop there.
> 

But... why? Why do we suddenly stop at "If both operands have the same 
type..."? We have a pointer and a bool. How is that "the same type", 
even if you promote the bool to an integer?

> I'm sorry - I thought it was /you/ who asked the original question, looking for help?  And the thanks I get for going through the paragraphs and explaining as best I can how I read the standards, is to get my head bitten off?
> 
> Maybe my understanding of the standards is not quite right.  Maybe my explanation wasn't great.  But if this is your idea of how to say "I don't see it that way, but thanks for trying", I'll leave you to figure things out some other way.  Perhaps someone else will reply to you, and maybe give you a reading that you'd prefer. 

Well, this was intended as a "language lawyer" kind of question. So, the 
help I was looking for does not allow for interpretations. I just needed 
a confirmation that what looks to me as a defect is indeed likely to be 
a defect.

-- 
Best regards,

[toc] | [prev] | [next] | [standalone]


#86337

FromTim Rentsch <tr.17687@z991.linuxsc.com>
Date2022-09-15 07:18 -0700
Message-ID<868rmkn2k7.fsf@linuxsc.com>
In reply to#85955
Andrey Tarasevich <andreytarasevich@hotmail.com> writes:

> On 8/16/2022 12:12 AM, David Brown wrote:
>
>>> Secondly, in any case these rules cannot be brushed off under "not
>>> triggered" premise because the very last rule in the list is a
>>> "sink":  it is not protected by a trigger at all, it is
>>> unconditional.  If none of the previous rules are "triggered" then
>>> the last rule applies:
>>>
>>>  http://eel.is/c++draft/expr.arith.conv#1.3.5
>>>  - Otherwise, both operands are converted to the unsigned integer
>>> type corresponding to the type of the operand with signed integer
>>> type.
>>>
>>> What do you expect this to do if one operand is a pointer?
>>
>> It doesn't get that far.  As I interpret this, only the bool gets
>> the "usual arithmetic conversions" - thus references to "both
>> operands" only apply to the single operand.  After the integral
>> promotions are performed (turning the bool into int), we get "If
>> both operands have the same type, no further conversion is needed"
>> and stop there.
>
> But... why?  Why do we suddenly stop at "If both operands have the
> same type..."?  We have a pointer and a bool.  How is that "the
> same type", even if you promote the bool to an integer?

It occurs to me that the problem here is not with the description
of additive operators (section 7.6.6) but with section 7.4, which
defines the usual arithmetic conversions.  What we have in the
case of a pointer and a bool is not two operands but one operand,
that is, just the bool (remember that 7.6.6 p1 says "The usual
arithmetic conversions are performed for operands of arithmetic
or enumeration type", which is just the bool operand in this
case).  Section 7.4 is written with the assumption that there
will be two operands being treated, but in this case there is
only one.  Thus a solution is to revise 7.4 so it addresses the
more general scenario of converting one or more operands.  Here
is a draft of a possible revision:


  Many operators that expect one or more operands of arithmetic
  or enumeration type cause conversions and yield result types in
  a similar way.  The purpose is to yield a common type, which is
  also the type of the result.  This pattern is called the usual
  arithmetic conversions, which are defined as follows:

  (1.1) -- If any operand is of scoped enumeration type no
  conversions are performed;  if any other operand does not have
  the same type, the expression is ill-formed.

  (1.2) -- If any operand is of type long double, all other
  operands shall be converted to long double.

  (1.3) -- Otherwise, if any operand is double, all other
  operands shall be converted to double.

  (1.4) -- Otherwise, if any operand is float, all other
  operands shall be converted to float.

  (1.5) -- Otherwise, the integral promotions shall be
  performed on all operands.  Then the following rules shall
  be applied to the promoted operands:

  (1.5.1) -- If all operands have the same type, no further
  conversion is needed.

  (1.5.2) -- Otherwise, if all operands have signed integer types
  or all operands have unsigned integer types, all operands with
  a type of lesser integer conversion rank shall be converted to
  an operand type having the greatest integer conversion rank.

  (1.5.3) -- Otherwise, if an operand that has unsigned integer
  type has an integer conversion rank that is greater than or
  equal to the rank of the type of all other operands, all other
  operands shall be converted to the type of the unsigned integer
  operand with the greatest integer conversion rank.

  (1.5.4) -- Otherwise, if the type of the operand with signed
  integer type can represent all of the values of the type of all
  other operands, those operands shall be converted to the type
  of the signed integer operand with the greatest integer
  conversion rank.

  (1.5.5) -- Otherwise, all operands shall be converted to the
  unsigned integer type corresponding to the type of an operand
  with signed integer type having the greatest integer conversion
  rank.

  2 If one operand is of enumeration type and any other operand
  is of a different enumeration type or a floating-point type,
  this behavior is deprecated.

Taking this approach solves the problem for section 7.6.6 and
also anticipates possible future additions to the language that
have more than two operands.

[toc] | [prev] | [next] | [standalone]


#86420

FromLanguage Lawyer <language.lawyer@gmail.com>
Date2022-09-19 03:28 -0700
Message-ID<b79ea01a-2cb1-4122-b335-14d0ca45c041n@googlegroups.com>
In reply to#86337
> Section 7.4 is written with the assumption that there  will be two operands being treated, but in this case there is  only one. Thus a solution is to revise 7.4 so it addresses the  more general scenario of converting one or more operands.

Or explicitly say in [expr.add] that the promotion is performed on the integer or enumeration operand, as [expr.unary.op] does (https://timsong-cpp.github.io/cppwp/n4861/expr.unary.op#7.sentence-2, https://timsong-cpp.github.io/cppwp/n4861/expr.unary.op#8.sentence-2, https://timsong-cpp.github.io/cppwp/n4861/expr.unary.op#10.sentence-2)

[toc] | [prev] | [next] | [standalone]


#86764

FromTim Rentsch <tr.17687@z991.linuxsc.com>
Date2022-10-02 12:37 -0700
Message-ID<86czbaj9th.fsf@linuxsc.com>
In reply to#86420
Language Lawyer <language.lawyer@gmail.com> writes:

>> Section 7.4 is written with the assumption that there  will be two
>> operands being treated, but in this case there is  only one.  Thus a
>> solution is to revise 7.4 so it addresses the  more general scenario
>> of converting one or more operands.
>
> Or explicitly say in [expr.add] that the promotion is performed on
> the integer or enumeration operand,

Seems like a bandaid.  I think it would be better to add a case
to the usual arithmetic conversions that covers the case of a
pointer and a non-pointer.

[toc] | [prev] | [next] | [standalone]


#85950

FromTim Rentsch <tr.17687@z991.linuxsc.com>
Date2022-08-15 14:36 -0700
Message-ID<86fshxur3q.fsf@linuxsc.com>
In reply to#85937
Andrey Tarasevich <andreytarasevich@hotmail.com> writes:

> Sound like a silly question (and it might just as well be), but
> nevertheless:
>
>    int *a = <whatever>;
>    bool b = true;
>    a + b;
>
> How does the binary `+` work in this case?  Its operands are an `int *`
> and a `bool`. `bool` is an integer type, so the requirements are met
> and the expression is valid.  Naturally we expect that `bool` to be
> promoted to an integer value of 1, and the rest is clear.
>
> But where does it say in the standard that `bool` should get promoted
> in this context?  There is no global rule requiring an unconditional
> promotion, i.e. each operator's specification mandates integral
> promotions individually and explicitly.  And I don't see integral
> promotions mentioned anywhere in [expr.add].
>
> It does mention usual arithmetic conversions (UAC), of course, and UAC
> include integral promotions.  But UAC are only applicable when _both_
> operands have enumeration or arithmetic type.  UAC are not applied when
> one operand is a pointer.  (The definition of UAC does not accommodate
> for such possibility.)
>
> So, how does pointer+bool addition work then?  When does `true` turn
> into 1 here?

Just a few comments..

One, I think you are raising a good point.

Two, my guess is that this issue reflects an oversight on the part
of the C++ standards committee.  At the very least, assuming there
is a provision in the C++ standard the gives this result, the
reasoning needed is obscure and deserves a note.

Three, an argument could be made (for C++20, n4860) that converting
'true' or 'false' to 1 or 0 is a consequence of the last sentence
of section 7.3 paragraph 1:

    A standard conversion sequence will be applied to an expression
    if necessary to convert it to a required destination type.

Granted, the reasoning is fraught with ambiguity, and that is never
good.  But the 'if necessary' provision gives a lot of latitude.

[toc] | [prev] | [next] | [standalone]


#85952

FromKeith Thompson <Keith.S.Thompson+u@gmail.com>
Date2022-08-15 14:57 -0700
Message-ID<87lerpcgqj.fsf@nosuchdomain.example.com>
In reply to#85950
Tim Rentsch <tr.17687@z991.linuxsc.com> writes:
> Andrey Tarasevich <andreytarasevich@hotmail.com> writes:
>
>> Sound like a silly question (and it might just as well be), but
>> nevertheless:
>>
>>    int *a = <whatever>;
>>    bool b = true;
>>    a + b;
>>
>> How does the binary `+` work in this case?  Its operands are an `int *`
>> and a `bool`. `bool` is an integer type, so the requirements are met
>> and the expression is valid.  Naturally we expect that `bool` to be
>> promoted to an integer value of 1, and the rest is clear.
>>
>> But where does it say in the standard that `bool` should get promoted
>> in this context?  There is no global rule requiring an unconditional
>> promotion, i.e. each operator's specification mandates integral
>> promotions individually and explicitly.  And I don't see integral
>> promotions mentioned anywhere in [expr.add].
>>
>> It does mention usual arithmetic conversions (UAC), of course, and UAC
>> include integral promotions.  But UAC are only applicable when _both_
>> operands have enumeration or arithmetic type.  UAC are not applied when
>> one operand is a pointer.  (The definition of UAC does not accommodate
>> for such possibility.)
>>
>> So, how does pointer+bool addition work then?  When does `true` turn
>> into 1 here?
>
> Just a few comments..
>
> One, I think you are raising a good point.
>
> Two, my guess is that this issue reflects an oversight on the part
> of the C++ standards committee.  At the very least, assuming there
> is a provision in the C++ standard the gives this result, the
> reasoning needed is obscure and deserves a note.
>
> Three, an argument could be made (for C++20, n4860) that converting
> 'true' or 'false' to 1 or 0 is a consequence of the last sentence
> of section 7.3 paragraph 1:
>
>     A standard conversion sequence will be applied to an expression
>     if necessary to convert it to a required destination type.
>
> Granted, the reasoning is fraught with ambiguity, and that is never
> good.  But the 'if necessary' provision gives a lot of latitude.

I think this is an oversight in the standard, and one that would be
fairly straightforward to correct.

The C standard, under "Additive operators", says:

    If both operands have arithmetic type, the usual arithmetic
    conversions are performed on them.

The corresponding wording in the C++ standard says:

    The usual arithmetic conversions are performed for operands of
    arithmetic or enumeration type.

The description of the "usual arithmetic conversions" is similar in both
standards, and assumes that both operands are of arithmetic type.  I
can't think of any good reason why the "If both operands have arithmetic
type," wording *should* apply in C but not in C++.

It *should* say that if one operand is of pointer type, the other
operand should undergo the integral promotions (but *not* the usual
arithmetic conversions).  So if you add a pointer and a bool, the bool
should be converted to int (0 or 1).

-- 
Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com
Working, but not speaking, for Philips
void Void(void) { Void(); } /* The recursive call of the void */

[toc] | [prev] | [next] | [standalone]


#85956

From"Alf P. Steinbach" <alf.p.steinbach@gmail.com>
Date2022-08-16 21:13 +0200
Message-ID<tdgq81$4lkc$1@dont-email.me>
In reply to#85937
On 15 Aug 2022 19:45, Andrey Tarasevich wrote:
> Hello
> 
> Sound like a silly question (and it might just as well be), but 
> nevertheless:
> 
>     int *a = <whatever>;
>     bool b = true;
>     a + b;
> 
> How does the binary `+` work in this case? Its operands are an `int *` 
> and a `bool`. `bool` is an integer type, so the requirements are met and 
> the expression is valid. Naturally we expect that `bool` to be promoted 
> to an integer value of 1, and the rest is clear.
> 
> But where does it say in the standard that `bool` should get promoted in 
> this context? There is no global rule requiring an unconditional 
> promotion, i.e. each operator's specification mandates integral 
> promotions individually and explicitly. And I don't see integral 
> promotions mentioned anywhere in [expr.add].
> 
> It does mention usual arithmetic conversions (UAC), of course, and UAC 
> include integral promotions. But UAC are only applicable when _both_ 
> operands have enumeration or arithmetic type. UAC are not applied when 
> one operand is a pointer. (The definition of UAC does not accommodate 
> for such possibility.)
> 
> So, how does pointer+bool addition work then? When does `true` turn into 
> 1 here?
> 

Looks like a little defect in the standard, including C++17 where there 
is contextual implicit conversion. cppreference lists the cases where 
that applies, <url: 
https://en.cppreference.com/w/cpp/language/implicit_conversion>. No, no 
`+` there.

And as far as I can see the problem for `+` is not only `bool` but also 
unscoped enumeration arg.

The `+` section (additive operators) states that if one arg is pointer 
then the other must be integral type or unscoped enumeration, but it 
then defines the effect only for integral type. Gah.

It does invoke usual arithmetic conversions, but that leads down to a 
self-contradiction: it's assumed that if the operand types are different 
after promotion then they must be unsigned and signed integral.

In short, it's a subtle mess, probably too unimportant for the committee 
to fix, or even an editorial fix. I guess Someone(tm) can check if 
there's a Defect Report for this. Maybe one was issued already for C++03.


- Alf

[toc] | [prev] | [next] | [standalone]


#85964

FromLanguage Lawyer <language.lawyer@gmail.com>
Date2022-08-17 09:08 -0700
Message-ID<808f24ee-8bf4-488d-85ce-dd2c1c0f8828n@googlegroups.com>
In reply to#85937
https://github.com/cplusplus/draft/issues/5199

[toc] | [prev] | [standalone]


Back to top | Article view | comp.lang.c++


csiph-web