GCC:由于数据类型的范围有限,比较总是如此 - 在模板参数中?

时间:2012-05-03 15:34:03

标签: c++ templates gcc comparison range

我想写一个模板,它返回可以表示给定数字的最小有符号整数类型。这是我的解决方案:

/**
 * Helper for IntTypeThatFits.
 * Template parameters indicate whether the given number fits into 8, 16 or 32
 * bits. If neither of them is true, it is assumed that it fits 64 bits.
 */
template <bool fits8, bool fits16, bool fits32>
struct IntTypeThatFitsHelper { };

// specializations for picking the right type
// these are all valid combinations of the flags
template<> struct IntTypeThatFitsHelper<true, true, true> { typedef int8_t Result; };
template<> struct IntTypeThatFitsHelper<false, true, true> { typedef int16_t Result; };
template<> struct IntTypeThatFitsHelper<false, false, true> { typedef int32_t Result; };
template<> struct IntTypeThatFitsHelper<false, false, false> { typedef int64_t Result; };

/// Finds the smallest integer type that can represent the given number.
template <int64_t n>
struct IntTypeThatFits
{
    typedef typename IntTypeThatFitsHelper<
        (n <= numeric_limits<int8_t>::max()) && (n >= numeric_limits<int8_t>::min()), 
        (n <= numeric_limits<int16_t>::max()) && (n >= numeric_limits<int16_t>::min()), 
        (n <= numeric_limits<int32_t>::max()) && (n >= numeric_limits<int32_t>::min())
    >::Result Result;
};

但是,GCC不接受此代码。我收到错误“由于数据类型的范围有限[-Werror = type-limits]”,因此比较总是如此。为什么会这样? n是带符号的64位整数,对于不同的n值,所有的比较可能都是真或假,或者我忽略了什么?

我会很高兴得到任何帮助。

编辑:我应该提到我正在使用C ++ 11。

5 个答案:

答案 0 :(得分:4)

这是gcc的一个问题,模板化代码中的警告可能令人沮丧。您可以更改警告或使用其他方法。

您可能知道,模板化代码会被分析两次:

  • 第一次遇到(解析)时
  • 一次实例化给定类型/值

这里的问题是,在实例化时,检查是微不足道的(是65适合int谢谢),并且编译器未能意识到此警告不适用于所有实例化: (对于我们这些努力在上发出警告的无警告编译经验的人来说,这确实令人非常沮丧。

您有三种可能性:

  • 停用此警告,或将其降级为非错误
  • 使用pragma为此代码选择性地停用它
  • 以其他格式重新编写代码,以便不再触发警告

请注意,有时第三种可能性涉及大规模变化和更复杂的解决方案。我建议不要使用复杂的代码 来摆脱无能的警告。

修改

一种可能的解决方法:

template <int64_t n>
struct IntTypeThatFits {
    static int64_t const max8 = std::numeric_limits<int8_t>::max();
    static int64_t const min8 = std::numeric_limits<int8_t>::min();

    static int64_t const max16 = std::numeric_limits<int16_t>::max();
    static int64_t const min16 = std::numeric_limits<int16_t>::min();

    static int64_t const max32 = std::numeric_limits<int32_t>::max();
    static int64_t const min32 = std::numeric_limits<int32_t>::min();

    typedef typename IntTypeThatFitsHelper<
        (n <= max8 ) && (n >= min8 ), 
        (n <= max16) && (n >= min16), 
        (n <= max32) && (n >= min32)
    >::Result Result;
};

...通过更改比较中使用的数据类型,它应该使编译器警告静音。我认为显式转换(int64_t(std::numeric_limits<int8_t>::max()))也可以工作,但我发现它更具可读性。

答案 1 :(得分:2)

错误正在发生,因为您要求GCC使用-Werror=type-limits向您提供有关此警告的错误。警告-Wtype-limits会在您进行比较时发出警告,由于给定数据类型的范围,该比较始终为真,例如:

uint8_t x;
if(x >= 0) { ... }  // always true, unsigned integers are non-negative
if(x >= 256) { ... }  // always false

int32_t x;
if(x < 9223372036854775808LL) { ... }  // always true

此警告有时可能有用,但在许多情况下,包括此警告只是无用的迂腐,可以忽略。它通常是一个警告(如果你使用的那样,是-Wextra的一部分启用),但是-Werror-Werror=type-limits,GCC会将其设为错误。

由于在这种情况下,它实际上并不表示您的代码存在潜在问题,因此只需使用-Wno-type-limits关闭警告,或者如果您不介意,请将其设为Werror=no-type-limits错误在编译器输出中看到这些警告。

答案 2 :(得分:1)

   typedef typename IntTypeThatFitsHelper<
        (n <= numeric_limits<int8_t>::max()) && (n >= numeric_limits<int8_t>::min()), 
        (n <= numeric_limits<int16_t>::max()) && (n >= numeric_limits<int16_t>::min()), 
        (n <= numeric_limits<int32_t>::max()) && (n >= numeric_limits<int32_t>::min())
    >::Result Result;

你不能在C ++中做到这一点(在C ++ 11中你可以) - numeric_limits<int8_t>::max()不是编译时常量。你在使用C ++ 11吗?

BTW,Boost已经为您提供了这个:http://www.boost.org/doc/libs/1_49_0/libs/integer/doc/html/boost_integer/integer.html

答案 3 :(得分:1)

我认为问题所在的其他答案是错误的。我不相信这是一个过度热衷的编译器的情况,但我相信这是一个编译器错误。此代码仍会触发警告:

template<int64_t n>
bool a() {
    return (n <= static_cast<int64_t>(std::numeric_limits<int8_t>::max()));
}

调用a<500>();时,但此代码不会:

template<int64_t n>
bool a() {
    return (n <= static_cast<int64_t>(127));
}

std :: numeric_limits :: max()的计算结果为127.如果没有其他人这样做,我今天晚些时候会提交bugzilla报告。

答案 4 :(得分:0)

你得到警告,因为对于template <int64_t n> struct IntTypeThatFits的一些小n(小于2 ^ 32)的瞬间,由于操作数的范围,一些比较总是正确的(原文!) em>在编译期间

在这种情况下,这可能被视为虚假警告,因为您的代码依赖于它,OTOH您明确要求使用-Werror或类似的命令行开关使其成为错误,您基本上得到您在此处所要求的