6
const auto min = -std::numeric_limits<T>::max();
T x = min; // conversion from 'const int' to 'short', possible loss of data

T is a template argument, a short in this case. Unary minus apparently performs integral promotion.

  • Why does unary minus perform integral promotion?
  • If auto is changed to T no warning is generated, but it should be assigning an int to a short. Why isn't there a warning (it could be VS being fancy)?
David
  • 27,652
  • 18
  • 89
  • 138
  • 4
    "Why does unary minus perform integral promotion?" Because the standard says so (in 5.3.1. (7)). – Daniel Fischer Aug 02 '12 at 20:15
  • 5
    @DanielFischer: But certainly there is a reason behind each decision made in forming the standard, no? It's not a bad thing to help people understand this reasoning if possible. – Ed S. Aug 02 '12 at 20:16
  • 3
    @EdS. Yes, hopefully there is a reason behind those decisions. I don't know the reasons for them, but I suspect this one is at least partially "because that's how it is in C". And why is it so in C? I suspect it's because it's simpler to let the CPU work on its native types and not convert the result back to the origin type. But that's just guesswork. – Daniel Fischer Aug 02 '12 at 20:22
  • 3
    @DanielFischer (1st comment): That answer irritates me so much (and I'm sure many other people) it's not even funny... – user541686 Aug 02 '12 at 20:39
  • @Mehrdad: In all fairness, it's a comment not an answer. –  Aug 02 '12 at 20:39
  • @0A0D: Touche... still, it's an "answer" to the question, posted as a comment. It's obvious what the OP is asking, since it's obvious he already made the observation that C++ behaves this way. – user541686 Aug 02 '12 at 20:39
  • 4
    Wouldn't it be weirder if some arithmetic operations followed integer promotion rules and some were exempt? Then you'd ask "Why are there two different sets of rules for when integer promotion gets applied? Why can't they be consistent?" – Raymond Chen Aug 02 '12 at 20:40
  • 1
    @Mehrdad: It is quite common for people to ask about the behavior or a particular compiler (*apparently performs integral promotion*) and stating (in a comment, not an answer) that the standard mandates so has value: it is making it clear that it is not a particular quirk or a concrete implementation but the behavior that should be expected in all compilers. The comment also contains a reference to the standard, which again is added value. You might not like it, but I don't think it is offensive or uncalled for. – David Rodríguez - dribeas Aug 02 '12 at 20:45
  • @Mehrdad: Sure.. OP asked "Why", Daniel could have been a little less terse and maybe more complete by explaining it completely, but it's not wrong. –  Aug 02 '12 at 20:45
  • @Mehrdad : Alternatively, his _compiler_ may behave that way, in conflict with what the standard allows/mandates. Citing the standard is __never__ a bad answer, and certainly never a bad comment. – ildjarn Aug 02 '12 at 20:47
  • @DavidRodríguez-dribeas: It's definitely not in the "offensive" category, and it's useful in a *technical* way, but it's in the "technically correct but practically useless for the OP" category. I've found that with these types of questions, if the OP was indeed seeking references to the C++ standard, he would've probably already looked, or asked for it. If he hasn't, then it's probably an indication that he's not interested in a "because the standard says so" answer. (i.e. another way to say this is, people care about the *motivations* behind decisions, not so much the decisions themselves.) – user541686 Aug 02 '12 at 20:47
  • @Mehrdad: Of course, but in the spirit of comment vs answer, drive-by's are OK when it comes to comments. –  Aug 02 '12 at 20:48
  • @Mehrdad: *(in 5.3.1. (7))* is useful. Now I can open the standard, and check what it has to say about integral promotions. – David Rodríguez - dribeas Aug 02 '12 at 20:49
  • @RaymondChen: "I *guess* it makes sense...", I can imagine the OP saying, if you remember which of your blog posts I'm referring to. :) – user541686 Aug 02 '12 at 20:53
  • 2
    You should be careful with `-std::numeric_limits::max()`. That expression does not yield the most negative value short can represent. You'd probably use that expression to get the most negative floating point number, but for integral types you want to use `numeric_limits::min()`. – bames53 Aug 02 '12 at 21:18

4 Answers4

6

Short answer: (now long because people want to be excessively pedantic about English which by its very nature is not exact).

Its not explicitly (as in the unary minus mathematical). But as part of any operation (this includes unary minus operation) on POD data there is an implicit check on input parameters (the smallest integer type that can be used in and operation is int) so there is integral promotion on the input before the unary minus (the mathematical part not the operation part). The output of all operations on POD is the same as the input parameters (after integral promotion is applied). Thus here the output is also an int.

Long answer:

In C (and thus C++) the smallest type that POD operations happen on is int. So before the unary minus is applied the value is converted to int. Then the unary minus is applied. The result of the expression is thus int.

See here: Implicit type conversion rules in C++ operators

Community
  • 1
  • 1
Martin York
  • 257,169
  • 86
  • 333
  • 562
4

Unary minus performs integral promotion because all the arithmetic operators on integral types do it. This convention was probably established for performance reasons (typically int was the size best suited for integral operations on the hardware) and perhaps because it's sometimes useful not to be limited to the range of smaller integral types.

I've seen bugs where people do:

uint64_t i = 1 << 33; // use 64-bit type to ensure enough bits to hold the result

But this is a bug because the result of 1 << 33 doesn't depend on what it's assigned to. (Today we have warnings about this). The solution, which is ugly, is to manually force one of the operands to be large enough: uint64_t i = static_cast<uint64_t>(1) << 33

Integral promotion happens to avoid the same sort of bug with smaller types, which would have been the common case back when C was designed this way:

short a = 30000, b = 20000
int i = a + b;

In any case "It doesn't have to be logical. It's the law."

bames53
  • 86,085
  • 15
  • 179
  • 244
0

I think this is to account for ideal computer model, which C/C++ assume. Calculations are performed in registers and it implies result's size would be machine word. Hence "automagical" expansion

Roman Saveljev
  • 2,544
  • 1
  • 21
  • 20
0

I believe it's (partly) because the negative of a short may not be representable as a short.
(-215 might need promotion to int if short is 16-bit and int is bigger.)

Of course, there's no guarantee that int is any bigger, but it's (usually?) the most optimal data type for the machine anyway, so it makes sense to try promoting it to int since there's likely no performance cost anyway.

user541686
  • 205,094
  • 128
  • 528
  • 886