Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/templates/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/google-cloud-platform/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++;安全整数强制转换模板 我试图编写C++模板函数,它将在不同的整数类型、不同的宽度以及可能的有符号/无符号不匹配的情况下,在整数溢出中抛出一个运行时异常。出于这些目的,我不关心从浮点类型转换为整数类型,也不关心其他对象到对象的转换。我想这样做,而不必编写大量的特殊情况下的代码。这就是我目前拥有的: template< typename T, typename R > void safe_cast( const T& source, R& result ) { // get the maximum safe value of type R R rMax = (R) ~0; if ( rMax < 0 ) // R is a signed type { // assume that we're on an 8-bit twos-compliment machine rMax = ~( 0x80 << ( ( sizeof( R ) - 1 ) * 8 ) ); } if ( ( source & rMax ) != source ) { throw new IntegerOverflowException( source ); } result = static_cast<R>( source ); } templatevoid safe_cast(常量T和源,R和结果) { //获取类型R的最大安全值 R rMax=(R)~0; 如果(rMax; 如果(从>加宽(toMax)){ 返回std::nullopt; }否则{ 返回(从); } }如果为constexpr,则为else(双签名){ 使用加宽=std::conditional_t sizeof(To))、From、To>; 如果(从>加宽(toMax)){ 返回std::nullopt; }否则如果(从_C++_Templates_Casting_Integer Overflow - Fatal编程技术网

C++;安全整数强制转换模板 我试图编写C++模板函数,它将在不同的整数类型、不同的宽度以及可能的有符号/无符号不匹配的情况下,在整数溢出中抛出一个运行时异常。出于这些目的,我不关心从浮点类型转换为整数类型,也不关心其他对象到对象的转换。我想这样做,而不必编写大量的特殊情况下的代码。这就是我目前拥有的: template< typename T, typename R > void safe_cast( const T& source, R& result ) { // get the maximum safe value of type R R rMax = (R) ~0; if ( rMax < 0 ) // R is a signed type { // assume that we're on an 8-bit twos-compliment machine rMax = ~( 0x80 << ( ( sizeof( R ) - 1 ) * 8 ) ); } if ( ( source & rMax ) != source ) { throw new IntegerOverflowException( source ); } result = static_cast<R>( source ); } templatevoid safe_cast(常量T和源,R和结果) { //获取类型R的最大安全值 R rMax=(R)~0; 如果(rMax; 如果(从>加宽(toMax)){ 返回std::nullopt; }否则{ 返回(从); } }如果为constexpr,则为else(双签名){ 使用加宽=std::conditional_t sizeof(To))、From、To>; 如果(从>加宽(toMax)){ 返回std::nullopt; }否则如果(从

C++;安全整数强制转换模板 我试图编写C++模板函数,它将在不同的整数类型、不同的宽度以及可能的有符号/无符号不匹配的情况下,在整数溢出中抛出一个运行时异常。出于这些目的,我不关心从浮点类型转换为整数类型,也不关心其他对象到对象的转换。我想这样做,而不必编写大量的特殊情况下的代码。这就是我目前拥有的: template< typename T, typename R > void safe_cast( const T& source, R& result ) { // get the maximum safe value of type R R rMax = (R) ~0; if ( rMax < 0 ) // R is a signed type { // assume that we're on an 8-bit twos-compliment machine rMax = ~( 0x80 << ( ( sizeof( R ) - 1 ) * 8 ) ); } if ( ( source & rMax ) != source ) { throw new IntegerOverflowException( source ); } result = static_cast<R>( source ); } templatevoid safe_cast(常量T和源,R和结果) { //获取类型R的最大安全值 R rMax=(R)~0; 如果(rMax; 如果(从>加宽(toMax)){ 返回std::nullopt; }否则{ 返回(从); } }如果为constexpr,则为else(双签名){ 使用加宽=std::conditional_t sizeof(To))、From、To>; 如果(从>加宽(toMax)){ 返回std::nullopt; }否则如果(从,c++,templates,casting,integer-overflow,C++,Templates,Casting,Integer Overflow,使用std::numeric_limits模板,例如std::numeric_limits::max(),您可以更优雅地获得任何基本类型的最小和最大安全值(以及大量其他信息)。您需要包括 参考资料:boost是一个选项吗?如果是,请尝试。它似乎提供了您要寻找的特征。您尝试过SafeInt吗?它是一个跨平台模板,可以对各种整数类型进行整数溢出检查。可在github上获得 我假设在R被签名的情况下,您试图用除最后一位之外的所有1填充rMax,是否正确?如果是这种情况,那么您应该使用0x80(10

使用
std::numeric_limits
模板,例如
std::numeric_limits::max()
,您可以更优雅地获得任何基本类型的最小和最大安全值(以及大量其他信息)。您需要包括


参考资料:

boost是一个选项吗?如果是,请尝试。它似乎提供了您要寻找的特征。

您尝试过SafeInt吗?它是一个跨平台模板,可以对各种整数类型进行整数溢出检查。可在github上获得


我假设在R被签名的情况下,您试图用除最后一位之外的所有1填充rMax,是否正确?如果是这种情况,那么您应该使用0x80(1000 0000)而不是0x10(0001 0000)

此外,您的函数似乎不支持源的负数

编辑:

下面是我测试过的一个稍微经过编辑的版本,用于将int转换为chars:

template< typename T, typename R >
void safe_cast( const T& source, R& result )
{
    // get the maximum safe value of type R
    R rMax = (R) ~0;
    if ( rMax < 0 ) // R is a signed type
    {
        // assume that we're on an 8-bit twos-compliment machine
    rMax = ( 0x80 << ( ( sizeof( R ) - 1 ) * 8 ) );
    if(source >= 0)
        rMax = ~rMax;
    }

    if ( (source >= 0 && ( source & rMax  ) != source) || (source < 0 && (source & rMax) != rMax) )
    {
        throw new IntegerOverflowException( source );
    }

    result = static_cast<R>( source );
}
模板
无效安全系数(常数T和源、R和结果)
{
//获取类型R的最大安全值
R rMax=(R)~0;
如果(rMax<0)//R是有符号类型
{
//假设我们在一个8位的两个恭维机器上
rMax=(0x80=0)
rMax=~rMax;
}
如果((震源>=0&&(震源和rMax)!=source)| |(震源<0&&(震源和rMax)!=rMax))
{
抛出新的IntegerOverflowException(源);
}
结果=静态投影(源);
}

编辑:已修复错误。

我认为无论您是否使用两个补码,这些现在都可以工作。请在使用之前进行广泛测试。它们给出以下结果。每行给出一个断言失败(请随意将它们更改为异常)

/*未签名->已签名,溢出*/
安全浇铸(UINT\U最大值);
/*未签名->未签名,溢出*/
安全铸造(ULONG_MAX);
/*已签名->未签名,溢出*/
安全浇铸(-1);
/*已签名->已签名,溢出*/
安全浇铸(内部最大值);
/*始终有效(未进行检查)*/
安全浇铸(内部最大值);
//给出这些断言失败的结果
(type)f=有符号::v_min&&f
结构转换;
/*这些转换永远不会溢出,如int->int,
*或int->long*/
模板
结构do_conv{
静态调用(从f){
返回(至)f;
}
};
模板
结构do_conv{
静态调用(从f){
断言(f=0);
返回(至)f;
}
};
模板
结构do_conv{
typedef typename uac_type::type type类型;
静态调用(从f){
断言(f>=0&(type)f如何:

template< typename T, typename R > void safe_cast( const T& source, R& result )
{
    R temp = static_cast<R>( source );
    if (static_cast<T> (temp) != source
        || ( temp < 0 && source > 0)
        || ( temp > 0 && source < 0))
    {
        throw IntegerOverflowException( source );
    }
    result = temp;
}

从int到char的转换工作正常。从char到unsigned char的转换会引发一个异常(应该是这样的)。我看不出这里有问题。

我肯定遗漏了什么,但这不是你想要的吗?:

// using a more cast-like prototype, if I may:
template<class to, class from> inline
to safe_cast(from f)
{
   to t = static_cast<to>(f);
   if ( t != f ) throw whatever; // no new!
   return t;
}
//如果可以的话,使用一个更像cast的原型:
模板内联
安全浇铸(从f开始)
{
to t=静态铸件(f);
如果(t!=f)抛出任何东西;//没有新的!
返回t;
}
我在conv.hpp中有一个标题名为conv.hpp。它将测试所有整数类型的边界,还允许对整数进行字符串强制转换

short a = to<short>(1337);
std::string b = to<std::string>(a);
long c = to<long>(b);
short a=to(1337);
std::字符串b=to(a);
长c=至(b);


<>这个库提供了所有C++本原整数类型的替换。当错误的结果被发现时,C的操作被包括了。(
std::optional
constexpr
type\u traits
)。下面是我写的:

/// Cast integer of type "From" to integer of type "To", as long as it fits. If it doesn't
/// fit, return std::nullopt.
template<typename To, typename From>
constexpr std::optional<To> IntegerCast(From from) {
    static_assert(std::is_integral_v<From>, "IntegerCast only supports integers");
    static_assert(std::is_integral_v<To>, "IntegerCast only supports integers");
    static_assert(!std::is_same_v<To, bool>, "IntegerCast only supports integers");
    static_assert(!std::is_same_v<From, bool>, "IntegerCast only supports integers");

    constexpr bool fromSigned = std::is_signed_v<From>;
    constexpr bool toSigned = std::is_signed_v<To>;
    constexpr bool bothSigned = fromSigned && toSigned;
    constexpr bool bothUnsigned = !fromSigned && !toSigned;

    constexpr From fromMax = std::numeric_limits<From>::max();
    constexpr From fromMin = std::numeric_limits<From>::min();
    constexpr To toMax = std::numeric_limits<To>::max();
    constexpr To toMin = std::numeric_limits<To>::min();

    if constexpr (bothUnsigned) {
        using Widen = std::conditional_t<(sizeof(From) > sizeof(To)), From, To>;
        if (from > Widen(toMax)) {
            return std::nullopt;
        } else {
            return To(from);
        }
    } else if constexpr (bothSigned) {
        using Widen = std::conditional_t<(sizeof(From) > sizeof(To)), From, To>;
        if (from > Widen(toMax)) {
            return std::nullopt;
        } else if (from < Widen(toMin)) {
            return std::nullopt;
        } else {
            return To(from);
        }
    } else if constexpr (fromSigned && !toSigned) {
        using Widen =
                std::make_unsigned_t<std::conditional_t<(sizeof(From) > sizeof(To)), From, To>>;
        if (from < 0) {
            return std::nullopt;
        } else if (from > Widen(toMax)) {
            return std::nullopt;
        } else {
            return To(from);
        }
    } else if constexpr (!fromSigned && toSigned) {
        using Widen =
                std::make_unsigned_t<std::conditional_t<(sizeof(From) > sizeof(To)), From, To>>;
        if (from > Widen(toMax)) {
            return std::nullopt;
        } else {
            return To(from);
        }
    }
}
///将“From”类型的整数强制转换为“to”类型的整数,只要合适。如果不合适
///拟合,返回std::nullopt。
模板
constexpr std::可选整数广播(从){
static_assert(std::is_integral_v,“IntegerCast仅支持整数”);
static_assert(std::is_integral_v,“IntegerCast仅支持整数”);
静态断言(!std::is_same_v,“IntegerCast仅支持整数”);
静态断言(!std::is_same_v,“IntegerCast仅支持整数”);
constexpr bool fromSigned=std::is_signed_v;
constexpr bool toSigned=std::is_signed_v;
constexpr bool botsigned=fromSigned&&toSigned;
constexpr bool bothUnsigned=!fromSigned&&!toSigned;
fromMax=std::numeric_limits::max()中的constexpr;
constexpr From fromMin=std::numeric_limits::min();
constexpr To toMax=std::numeric_limits::max();
constexpr To toMin=std::numeric_limits::min();
如果constexpr(bothUnsigned){
使用加宽=std::conditional_t sizeof(To))、From、To>;
如果(从>加宽(toMax)){
返回std::nullopt;
}否则{
返回(从);
}
}如果为constexpr,则为else(双签名){
使用加宽=std::conditional_t sizeof(To))、From、To>;
如果(从>加宽(toMax)){
返回std::nullopt;
}否则如果(从<加宽(toMin)){
返回std::nullopt;
}否则{
返回(从);
}
}else if constexpr(从已签名&&!到已签名){
使用加宽=
标准::m
int myint (-1);
safe_cast( myint, mychar );
safe_cast( mychar, myuchar ); // Exception is thrown here
safe_cast( myuchar, myint );
// using a more cast-like prototype, if I may:
template<class to, class from> inline
to safe_cast(from f)
{
   to t = static_cast<to>(f);
   if ( t != f ) throw whatever; // no new!
   return t;
}
short a = to<short>(1337);
std::string b = to<std::string>(a);
long c = to<long>(b);
/// Cast integer of type "From" to integer of type "To", as long as it fits. If it doesn't
/// fit, return std::nullopt.
template<typename To, typename From>
constexpr std::optional<To> IntegerCast(From from) {
    static_assert(std::is_integral_v<From>, "IntegerCast only supports integers");
    static_assert(std::is_integral_v<To>, "IntegerCast only supports integers");
    static_assert(!std::is_same_v<To, bool>, "IntegerCast only supports integers");
    static_assert(!std::is_same_v<From, bool>, "IntegerCast only supports integers");

    constexpr bool fromSigned = std::is_signed_v<From>;
    constexpr bool toSigned = std::is_signed_v<To>;
    constexpr bool bothSigned = fromSigned && toSigned;
    constexpr bool bothUnsigned = !fromSigned && !toSigned;

    constexpr From fromMax = std::numeric_limits<From>::max();
    constexpr From fromMin = std::numeric_limits<From>::min();
    constexpr To toMax = std::numeric_limits<To>::max();
    constexpr To toMin = std::numeric_limits<To>::min();

    if constexpr (bothUnsigned) {
        using Widen = std::conditional_t<(sizeof(From) > sizeof(To)), From, To>;
        if (from > Widen(toMax)) {
            return std::nullopt;
        } else {
            return To(from);
        }
    } else if constexpr (bothSigned) {
        using Widen = std::conditional_t<(sizeof(From) > sizeof(To)), From, To>;
        if (from > Widen(toMax)) {
            return std::nullopt;
        } else if (from < Widen(toMin)) {
            return std::nullopt;
        } else {
            return To(from);
        }
    } else if constexpr (fromSigned && !toSigned) {
        using Widen =
                std::make_unsigned_t<std::conditional_t<(sizeof(From) > sizeof(To)), From, To>>;
        if (from < 0) {
            return std::nullopt;
        } else if (from > Widen(toMax)) {
            return std::nullopt;
        } else {
            return To(from);
        }
    } else if constexpr (!fromSigned && toSigned) {
        using Widen =
                std::make_unsigned_t<std::conditional_t<(sizeof(From) > sizeof(To)), From, To>>;
        if (from > Widen(toMax)) {
            return std::nullopt;
        } else {
            return To(from);
        }
    }
}
TEST(IntegerCast, Basics) {
    constexpr uint64_t large64 = 10000000000000000000ull;
    static_assert(IntegerCast<uint8_t>(large64) == std::nullopt);
    static_assert(IntegerCast<uint16_t>(large64) == std::nullopt);
    static_assert(IntegerCast<uint32_t>(large64) == std::nullopt);
    static_assert(IntegerCast<uint64_t>(large64) == 10000000000000000000ull);
    static_assert(IntegerCast<int8_t>(large64) == std::nullopt);
    static_assert(IntegerCast<int16_t>(large64) == std::nullopt);
    static_assert(IntegerCast<int32_t>(large64) == std::nullopt);
    static_assert(IntegerCast<int64_t>(large64) == std::nullopt);

    constexpr int64_t largeNegative64 = -5000000000000000000;
    static_assert(IntegerCast<uint8_t>(largeNegative64) == std::nullopt);
    static_assert(IntegerCast<uint16_t>(largeNegative64) == std::nullopt);
    static_assert(IntegerCast<uint32_t>(largeNegative64) == std::nullopt);
    static_assert(IntegerCast<uint64_t>(largeNegative64) == std::nullopt);
    static_assert(IntegerCast<int8_t>(largeNegative64) == std::nullopt);
    static_assert(IntegerCast<int16_t>(largeNegative64) == std::nullopt);
    static_assert(IntegerCast<int32_t>(largeNegative64) == std::nullopt);
    static_assert(IntegerCast<int64_t>(largeNegative64) == -5000000000000000000);

    constexpr uint64_t small64 = 1;
    static_assert(IntegerCast<uint8_t>(small64) == 1);
    static_assert(IntegerCast<uint16_t>(small64) == 1);
    static_assert(IntegerCast<uint32_t>(small64) == 1);
    static_assert(IntegerCast<uint64_t>(small64) == 1);
    static_assert(IntegerCast<int8_t>(small64) == 1);
    static_assert(IntegerCast<int16_t>(small64) == 1);
    static_assert(IntegerCast<int32_t>(small64) == 1);
    static_assert(IntegerCast<int64_t>(small64) == 1);

    constexpr int64_t smallNegative64 = -1;
    static_assert(IntegerCast<uint8_t>(smallNegative64) == std::nullopt);
    static_assert(IntegerCast<uint16_t>(smallNegative64) == std::nullopt);
    static_assert(IntegerCast<uint32_t>(smallNegative64) == std::nullopt);
    static_assert(IntegerCast<uint64_t>(smallNegative64) == std::nullopt);
    static_assert(IntegerCast<int8_t>(smallNegative64) == -1);
    static_assert(IntegerCast<int16_t>(smallNegative64) == -1);
    static_assert(IntegerCast<int32_t>(smallNegative64) == -1);
    static_assert(IntegerCast<int64_t>(smallNegative64) == -1);
}

TEST(IntegerCast, Boundaries) {
    constexpr uint8_t maxUnsigned8 = 255;
    static_assert(IntegerCast<uint8_t>(maxUnsigned8) == 255);
    static_assert(IntegerCast<uint16_t>(maxUnsigned8) == 255);
    static_assert(IntegerCast<uint32_t>(maxUnsigned8) == 255);
    static_assert(IntegerCast<uint64_t>(maxUnsigned8) == 255);
    static_assert(IntegerCast<int8_t>(maxUnsigned8) == std::nullopt);
    static_assert(IntegerCast<int16_t>(maxUnsigned8) == 255);
    static_assert(IntegerCast<int32_t>(maxUnsigned8) == 255);
    static_assert(IntegerCast<int64_t>(maxUnsigned8) == 255);

    constexpr uint8_t minUnisigned8 = 0;
    static_assert(IntegerCast<uint8_t>(minUnisigned8) == 0);
    static_assert(IntegerCast<uint16_t>(minUnisigned8) == 0);
    static_assert(IntegerCast<uint32_t>(minUnisigned8) == 0);
    static_assert(IntegerCast<uint64_t>(minUnisigned8) == 0);
    static_assert(IntegerCast<int8_t>(minUnisigned8) == 0);
    static_assert(IntegerCast<int16_t>(minUnisigned8) == 0);
    static_assert(IntegerCast<int32_t>(minUnisigned8) == 0);
    static_assert(IntegerCast<int64_t>(minUnisigned8) == 0);

    constexpr int8_t maxSigned8 = 127;
    static_assert(IntegerCast<uint8_t>(maxSigned8) == 127);
    static_assert(IntegerCast<uint16_t>(maxSigned8) == 127);
    static_assert(IntegerCast<uint32_t>(maxSigned8) == 127);
    static_assert(IntegerCast<uint64_t>(maxSigned8) == 127);
    static_assert(IntegerCast<int8_t>(maxSigned8) == 127);
    static_assert(IntegerCast<int16_t>(maxSigned8) == 127);
    static_assert(IntegerCast<int32_t>(maxSigned8) == 127);
    static_assert(IntegerCast<int64_t>(maxSigned8) == 127);

    constexpr int8_t minSigned8 = -128;
    static_assert(IntegerCast<uint8_t>(minSigned8) == std::nullopt);
    static_assert(IntegerCast<uint16_t>(minSigned8) == std::nullopt);
    static_assert(IntegerCast<uint32_t>(minSigned8) == std::nullopt);
    static_assert(IntegerCast<uint64_t>(minSigned8) == std::nullopt);
    static_assert(IntegerCast<int8_t>(minSigned8) == -128);
    static_assert(IntegerCast<int16_t>(minSigned8) == -128);
    static_assert(IntegerCast<int32_t>(minSigned8) == -128);
    static_assert(IntegerCast<int64_t>(minSigned8) == -128);
}

TEST(IntegerCast, SameSizeDifferentSign) {
    constexpr uint8_t above = 200;
    static_assert(IntegerCast<int8_t>(above) == std::nullopt);

    constexpr uint8_t withinUnsigned = 100;
    static_assert(IntegerCast<int8_t>(withinUnsigned) == 100);

    constexpr int8_t withinSigned = 100;
    static_assert(IntegerCast<uint8_t>(withinSigned) == 100);

    constexpr int8_t below = -100;
    static_assert(IntegerCast<uint8_t>(below) == std::nullopt);
}