0

I've been trying to make signed literal short hands for <cstdint> types, for example, u8, u16, etc...

I developed a function like this:

constexpr std::int8_t operator "" _i8(unsigned long long int value){
    unsigned long long int mask = 0xEF;
    if(value && mask == value){
        return static_cast<std::int8_t>(value);
    }else{
        throw std::out_of_range("");
    }
}

I then looked up and found that - is actually not part of the literal. What this means for me is that the above code( if it included 128, right now it doesn't) wouldn't actually work correctly for -128.

When I try this out in godbolt

#include <type_traits> 
#include <iostream> 
#include <cstdint> 
#include <bitset> 


int main(){

    std::cout << std::bitset<8>(static_cast<std::int8_t>(128)) << std::endl; 
    std::cout << static_cast<std::int32_t>(static_cast<std::int8_t>(128)) << std::endl; 
    std::cout << static_cast<std::int32_t>(static_cast<std::int8_t>(-128)) << std::endl; 
    std::cout << static_cast<std::int32_t>(-static_cast<std::int8_t>(128)) << std::endl; 
    return 0; 
}

I get 10000000, -128, -128, and 128

Technically using 128 could work in the above example, it would just force the value to be -128 on the output, but when they (correctly) add a negative, it will turn into 128, and not be a int8_t. I'd like errors on 128 with no negative, and no errors on 128 with negative.

I thought about making some sort of temporary object with - overloaded for it, and implicitly converting, but even with that, it won't work properly in template functions, so the unary - operator would have to return the base type, and I would somehow have to return the base type switched on if the value is 128 or not, but I don't think that's possible.

I basically want the following to work:

template<typename T> 
foo(const T& bar, const T& baz); 

foo(127_i8, std::int8_t(32));
foo(-128_i8, std::int8_t(32));

and this to not work:

foo(128_i8, std::int8_t(32));
Krupip
  • 4,404
  • 2
  • 32
  • 54
  • You've found one of the sharp edges in C++ (and in C). – Eljay Oct 12 '21 at 22:39
  • A related question: is there a way to tell if the implementation is using 2s complement or 1's complement? All the platforms I've developed for have been 2's complement, but I know there are 1's complement platforms out there. – Thomas Matthews Oct 12 '21 at 23:03
  • 1
    @ThomasMatthews AFAIK, C++20 now requires signed integers to be two's complement, see P1236R1. – heap underrun Oct 12 '21 at 23:16

0 Answers0