1

I have following C++11 code using templates:

struct Base{
    using count_type = unsigned short;
};

template<class T>
struct A : public Base{
    using count_type = A::count_type;
    // not works even if I comment this

    count_type add(T x){
        count_type sum = 5;
        sum += x.value(); 
        //sum += (count_type) x.value(); // not works even if I cast this, e.g.


        return sum;
    }
};

struct B{
    using count_type = A<B>::count_type;

    count_type value(){
        return 5; // not works even if I do:
        //return (count_type) 5;
        //return 5U;
    }
};

int main(int argc, char *argv[]){
    B b;

    A<B> a;

    a.add(b);
}

When I try to compile with -Wconversion, I get strange error message:

$ g++ -std=c++11  -Wconversion x.cc
x.cc: In instantiation of ‘A<T>::count_type A<T>::add(T) [with T = B; A<T>::count_type = short unsigned int]’:
x.cc:29:9:   required from here
x.cc:11:7: warning: conversion to ‘A<B>::count_type {aka short unsigned int}’ from ‘int’ may alter its value [-Wconversion]
   sum += x.value();
       ^

Why this happens? There is no int anywhere?

I will be grateful if someone edit my question.

Note: clang does not give such warning.

Nick
  • 9,962
  • 4
  • 42
  • 80

2 Answers2

1

sum += x.value(); means (roughly) sum = sum + x.value(); The RHS here, sum + x.value(), adds two unsigned short values and produces an int. Assigning that int back to an unsigned short can alter its value.

The warning is, in my opinion, not particularly useful and I suggest turning it off, but if you want to keep it enabled for some reason, write a cast there:

sum = (count_type) (sum + x.value());

or

sum = static_cast<count_type>(sum + x.value());
  • this is it!!! but why this not happen when type is not template-dependent? – Nick Dec 13 '15 at 15:08
  • 1
    @LightnessRacesinOrbit The OP tried `sum += (count_type) x.value();`. That won't work, and it's not what I have in my answer. –  Dec 13 '15 at 15:08
  • 1
    @LightnessRacesinOrbit i casted sum = sum + (count_type) x.value(); – Nick Dec 13 '15 at 15:09
  • @Nick: you must not cast the operand but the result of the operation, eg `sum = (count_type)(sum + x.value())`. – Jack Dec 13 '15 at 15:09
  • 1
    @Nick I get the warning even if the type is not template-dependent. –  Dec 13 '15 at 15:10
1

According to implicit promotions, any arithmetic expression (as sum = sum + x.value()) undergoes a pattern called usual arithmetic conversions, the relevant part from §5 of the standard:

...

— Otherwise, the integral promotions (4.5) shall be performed on both operands. 59 Then the following rules shall be applied to the promoted operands:

The integral promotions specifies:

A prvalue of an integer type other than bool, char16_t, char32_t, or wchar_t whose integer conversion rank (4.13) 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.

So operands are converted to int, then back to unsigned short. This because the conversion rank specifies that

The rank of a signed integer type shall be greater than the rank of any signed integer type with a smaller size.

and

The rank of any unsigned integer type shall equal the rank of the corresponding signed integer type.

Jack
  • 131,802
  • 30
  • 241
  • 343