Meta-programming, promoting a type without changing the sign

Today I found that one of my functions would overflow. Here is a simplified version of it:

template<typename T>
T scale(T value, T position, T count)
{
    return (value * position) / count;
}

As we can see, all variables are of type T. So if the multiplication overflows, the function returns an invalid result. To fix this, I wanted to promote all the variables to the latest possible integer (keeping the sign) or double (in my case the support for floating points was just for the type float so no need for long double.)

As a result I wrote a structure using meta-programming as follow:

template<typename T>
struct largest_type
{
    typedef typename std::conditional<
         std::is_floating_point<T>::value
         , double
         , typename std::conditional<
           std::is_signed<T>::value
             , std::intmax_t
             , std::uintmax_t>::type>::type type;
    };

Now I can create a type as follow:

typedef typename largest_type<T>::type largest_t;

Then I can use that largest_t type to cast my variables before doing the computation:

template<typename T>
T scale(T value, T position, T count)
{
    typedef typename largest_type<T>::type largest_t;
    return static_cast<T>((
         static_cast<largest_t>(value)
       * static_cast<largest_t>(position))
       / static_cast<largest_t>(count);
}

Now the operation works because the type does not overflow anymore and I did not have to specify another template parameter to the 28 references of that scale() templete.