c++templatesvisual-c++-2005size-tvisual-studio

"size_t" as type parameter, cast warning not reproduced


I've been trying to get rid of warnings in some older code (must use MSVC 2005, currently working with a 32 bit build), but have been struggling to get rid of a size_t to unsigned int conversion warning. We have our own Array<T> implementation of a growing array that implements an

template<typename I> const T& at(const I i) const {return atImpl(i);}

method. When called as

size_t i = 10; myArray.at(i);

I get a conversion from 'size_t' to 'const unsigned int', possible loss of data warning. A working theory has been that I is understood to be unsigned int, which is causing compiler to cast/convert the size_t to unsigned int when passing i to at (which would have been inconvenient but acceptable). However, I haven't been able to reproduce this warning in neither a minimal working example (bottom of this post), nor in more complex minimal examples. Simply casting the parameter to unsigned int makes the warning disappear and would be enough for our needs (by contract, the number fits within an unsigned int)

  1. Is my understanding about I being unsigned int in such a call correct (spec says "A typedef-name is thus a synonym for another type. A typedef-name does not introduce a new type", typeid(size_t(1)).name() says unsigned int and size_t seems to be typedeffed). In other words, should or should not the minimal example give the warning? The build configuration is the same, as far as I can tell.
  2. As our code gives us warnings and the minimal example doesn't, there's something I must be overlooking. Despite all effort, I can't figure out what. Ideas?

Thanks

The minimal example:

    template<typename T>
    class A
    {
      int t;
    public:
      template<typename I> T& at(const I i) { return t;}  
    };

    int main()
    {  
      size_t i = 10;
      A<int> a; 
      a.at(i) = 5; // no warning, why?
      return 0;
    }

Solution

  • The at function is also templated. C++ will try to deduce the template type argument. Which is what is happening in your code since you are not specifying the type in the call such as a.at< size_t>(1);

    This code will generate a warning because it has deduced the type as a unsigned int and then we try to pass an size_t

    template <typename T>
    class A
    {
        int t;
        public:
            template<typename I> T& at(const I i)
            { return t;}
    };
    
    int main()
    {
        unsigned int j = 5;
        size_t i = 10;
        A<int> a;
    
        a.at(j) = 4; // deduce template type as unsigned int
        a.at(i) = 5; // generate warning
        return 0;
    }
    

    EDIT: I actually tried this code in VS and it generates the warning.

    Edit2: In the code I tried size_t and unsigned int are both also 4 bytes. So I did some digging. In older versions of VS size_t is defined as typedef __w64 unsigned int size_t The '__w64' is now deprecated but was used to flag types that would have a different size (eg 64 vs 32) when moving to a 64 bit platform. The __w64 causes the compiler to see size_t as a different type.

    As an experiment I typedefed my own unsigned int myint and changed the line size_t i = 10 to myint i = 10.

    using typedef __w64 unsigned int myint generates the warning where as 'typedef unsigned int myint` does not generate a warning.