如何制作考虑 2 补码的小有符号整数文字?

问题描述 投票:0回答:1

我一直在尝试为

<cstdint>
类型制作有符号文字简写,例如 u8、u16 等...

我开发了这样的功能:

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("");
    }
}

然后我抬头发现

-
实际上不是字面值的一部分。这对我来说意味着上面的代码(如果它包含 128,现在不包含)实际上对于 -128 无法正常工作。

当我在 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; 
}

我得到

10000000
-128
-128
128

从技术上讲,使用 128 可以在上面的示例中工作,它只会强制输出上的值为 -128,但是当他们(正确地)添加负数时,它将变成 128,而不是 int8_t。我希望 128 上没有负数错误,并且 128 上没有负数错误。

我考虑过创建某种临时对象,并为其重载

-
,并隐式转换,但即使这样,它也无法在模板函数中正常工作,因此一元 - 运算符必须返回基本类型,如果值是 128 或不是 128,我会以某种方式返回打开的基本类型,但我认为这是不可能的。

我基本上希望以下工作能够发挥作用:

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

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

这不起作用:

foo(128_i8, std::int8_t(32));
c++ type-conversion integer user-defined-literals
1个回答
0
投票

即使对于 C++20,现在要求有符号整数是二进制补码,这也是不可能的,因为不存在负整数文字这样的东西。这意味着模仿负整数文字始终是一个两步过程。如果不首先创建

-128_i8
,就无法创建
128_i8
,并且在这一点(第一步),不知道稍后是否会对其应用某种否定操作。

所以,虽然我们可以做类似this的事情来使

static_assert(-128_i8 == -128);
编译成功。

// note: this example assumes that the implementation defined
//   truncation does the right thing
#include <cstdint>

struct [[nodiscard]] i8 {
    [[nodiscard]]
    consteval auto operator-() const noexcept -> i8
    { return {static_cast<std::int8_t>(-n)}; }

    [[nodiscard]]
    consteval operator std::int8_t() const noexcept
    { return n; }

    std::int8_t n;
};

[[nodiscard]]
consteval auto operator""  _i8(unsigned long long int n) noexcept -> i8
{ return {static_cast<std::int8_t>(n)}; }

static_assert(-128_i8 == -128);
static_assert((128_i8).operator-() == -128);

在创建用户定义文字时,仍然无法区分

128_i8
-128_i8
。我们在这里能做的最好的事情就是匹配底层整数类型的截断行为。

static_assert(-128_i8 == 128_i8);
static_assert(static_cast<std::int8_t>(-128) == static_cast<std::int8_t>(128));
© www.soinside.com 2019 - 2024. All rights reserved.