in case of unwanted integral promotion you might want to look at my integer replacement library that does not silently promote and change signedness or signed integer overflow undefined behavior by employing enum class types:

https://github.com/PeterSommerlad/PSsimplesafeint

Regards
Peter

Sent from Peter Sommerlad's iPad
+41 79 432 23 32

On 30 Apr 2022, at 10:07, Frederick Virchanza Gotham via Std-Proposals <std-proposals@lists.isocpp.org> wrote:

On Fri, Mar 25, 2022 at 11:09 AM organicoman wrote:

Your proposal could be interesting.
But why do you want to explicitly write the type, if you can deduce it?


One common debacle in C++ is unwanted integer promotion, especially
for beginner programmers. Let's say we have a template function whose
return type is the same as its parameter type:

   template<typename T>
   T Func(T const &arg) {    /* Do something */   }

And let's say we do this:

   int main(void)
   {
       char unsigned a = 7, b = 6;

       Func( a + b );
   }

Lots of people at first glance will think here that 'Func' is being
instantiated with the type "char unsigned", when really it's being
instantiated with "int".
If the template function, 'Func', will be frequently used in such a
context, it would be better for the programmer to have to explicitly
specify the type, either:

   Func<char unsigned>(a+b);

or even:

   Func<decltype(a)>(a+b);

In my day job I write C++ for an Arduino microcontroller. I went
looking in my code just now to find the template function I wrote
earlier this month. The following function performs the mathematical
operation:

   a + b

however if this operation results in overflow then it returns:

   std::numeric_limits<T>::max();

So here's how I wrote the function:

#include <type_tratis>

template<typename T>
typename std::common_type<T>::type Add_Or_Max(T const a, T const b)
{
   static_assert( false == std::numeric_limits<T>::is_signed,
"Add_Or_Max can only be used with an unsigned integer type" );

   if ( a > (std::numeric_limits<T>::max() - b) )
   {
       return std::numeric_limits<T>::max();
   }
   else
   {
       return a + b;
   }
}

My program runs on an Arduino microcontroller, however I also compile
it as part of a simulator that runs on an x86_64 desktop PC. In the
future the simulator might run on a different kind of desktop PC, and
we might change to a 16-Bit or 64-Bit microcontroller (or even 8-Bit
-- Arduino has a C++ compiler for 8-Bit). Because of the differences
in architecture here, I am very particular about integer types, using
"std::uint16_t" and "std::int32_t" instead of short, int, long (and
also watching out for the perils of integer promotion -- e.g. uint32_t
might promote to a signed 64-Bit number). When a programmer uses my
function "Add_Or_Max", I want it to stick out like a sore thumb in the
code which integer type they're using, e.g.:

   #include <cstdint>
   using std::uint16_t;

   uint16_t my_global_var;

   int main(void)
   {
       Add_Or_Max( my_global_var, 52u );  // I don't want this to compiler

       Add_Or_Max<uint16_t>( my_global_var, 52u );  // I want this to compile
   }

And so I think it would be great if we could have explicit template
parameters as follows:

template<explicit typename T>
T Add_Or_Max(T const a, T const b)
{
   static_assert( false == std::numeric_limits<T>::is_signed,
"Add_Or_Max can only be used with an unsigned integer type" );

   if ( a > (std::numeric_limits<T>::max() - b) )
   {
       return std::numeric_limits<T>::max();
   }
   else
   {
       return a + b;
   }
}
--
Std-Proposals mailing list
Std-Proposals@lists.isocpp.org
https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals