Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

auto type deduction not working as expected

this is much like this question Why must a short be converted to an int before arithmetic operations in C and C++? however there is a sub-question why the compiler diagnoses a warning in one case and an error in the other case ,with the exact same expression.

I really like the use of the auto 'type' as in auto var =..., but MSVC 2015 CTP gives an error from my code.

The issue is I am auto-ing an expression of type short but sometimes it's promoted to int.

Here's a MCVE:

struct MY_COORD { short X; short Y; };
using t_crd = MY_COORD; 

void call_test ( t_crd x )  {}

int main()
{
    t_crd    crd { 10 ,20 };

    auto     x5 = crd.X - crd.Y;
    auto     y5 = crd.Y - crd.X;
    t_crd    crd5 { x5 ,y5 };       // (1)
    call_test( t_crd{ x5 ,y5 } );   // (2)
}

The messages from lines (1) and (2) are respectively:

 warning C4838: conversion from 'int' to 'short' requires a narrowing conversion
 error C2397: conversion from 'int' to 'short' requires a narrowing conversion

I thought this code was OK but it's not according to MSVC 2015 CTP compiler (but Intellisense doesn't indicate it). Is there some obscure little rule that I missed that makes MSVC right ?

And if so why is the same expression a warning in one case and an error in the other case ?

I wanted to use it in the initialization of a loop variable like this:

MY_COORD pos = ResultFromFunction();
auto rows = pos.Y;
for ( auto i = (rows - rows); i < rows; ++i )
{
   coord c{ 0 ,i };
   ...
}
like image 202
engf-010 Avatar asked Feb 11 '23 16:02

engf-010


1 Answers

Arithmetic operators always promote integral types smaller than int to int before performing the operation. This is mandated in [expr]/10 of the C++11 standard:

Many binary operators that expect 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.

The sub-clause from there which applies to your case specifies that the operands in rows - rows will be subjected to integral promotion. In particular, according to [conv.prom]/1

A prvalue of an integer type other than bool, char16_t, char32_t, or wchar_t whose integer conversion rank is less than the rank of int can be converted to a prvalue of type int if int can represent all the values of the source type; otherwise, the source prvalue can be converted to a prvalue of type unsigned int.

Since the rank of short is guaranteed to be less than the rank of int, both the operands of rows - rows are promoted to int, giving the expression rows - rows a type of int.

About the narrowing conversion, the standard specifies(in [dcl.init.aggr]) that, in aggregate initialization, if the expression requires a narrowing conversion, the program is ill-formed. Compilers are free to diagnose it anyway they like. IIRC, under the simple circumstances like t_crd crd5 { x5 ,y5 };, clang 3.5 issues an error while g++ 4.9.2 issues a warning when used with the default warnings settings. Either way. MSVC's behaviour, even if slightly odd, is standard-conforming.

like image 166
Pradhan Avatar answered Feb 16 '23 07:02

Pradhan