【问题标题】:Using -Wtype-limits with type generic code将 -Wtype-limits 与类型泛型代码一起使用
【发布时间】:2020-02-29 06:59:10
【问题描述】:

我有一个对泛型类型的值执行否定检查的函数(我不想假设该类型,它不一定是模板化的)。但是,启用-Wtype-limits 后,如果所讨论的类型是无符号类型,编译器会抱怨否定检查。如果类型可能更改为有符号类型,则删除否定检查是一个坏主意,并且禁用警告并不理想,因为它可能会发现合法问题。

using example_t = uint8_t;   // could be int8_t or int64_t or really whatever integer type that can store values 0 - 8.

void example(example_t value) {
    if (value < 0 || value >= 9) {  // <-- errors on the 'value < 0' check
        throw std::invalid_argument("some error message");
    }
    // continue processing ...
}

即使我使用 C++17 并使用 if constexpr(std::is_unsigned&lt;example_t&gt;::value) 来保护正在警告的检查,它仍然会发出警告。我注意到 GCC 不会为if constexpr'd out 代码发出警告,如果它会触发警告,因为分配给这些类型的变量的值会超出类型的范围。此外,即使我先将其转换为signed int,GCC 也会发出警告。警告行为与自身不一致,因此这似乎是一个错误。对于这些类型的检查,Clang 根本不会发出警告。

但我想知道是否有办法解决这个问题,我的代码库严格符合 C++14,而且我们被旧的 GCC 编译器困住了。

【问题讨论】:

    标签: c++ gcc clang c++14


    【解决方案1】:

    我不确定对可读性的影响是否值得,但您可以使用通用 lambda 将比较移动到模板上下文中。 GCC 不会在模板代码中对此发出警告:

    if ([](auto v){return v < 0;}(value) || value >= 9)
    

    或者最好写一个函数:

    template<typename T>
    constexpr bool is_negative(T t) { return t < 0; }
    

    并使用它:

    if (is_negative(value) || value >= 9)
    

    或者只使用std::less也不会发出警告:

    if (std::less()(value, 0) || value >= 9)
    

    GCC 还有#pragmas 可以暂时禁用警告,请参阅this question

    #pragma GCC diagnostic push
    #pragma GCC diagnostic ignored "-Wtype-limits"
    if (value < 0 || value >= 9) {
        throw std::invalid_argument("some error message");
    }
    #pragma GCC diagnostic pop
    

    【讨论】:

    • is_negative 方法对我来说似乎是最佳选择。比 lambda 更易读(并且在 C++14 的 constexpr 函数中工作)并且比 pragma 更便携。
    • @ktb 啊,是的,我忘记了 lambda 仅在 C++17 之后才允许在常量表达式中使用。 std::less 方法也应该可用于 C++14 中的常量表达式。
    猜你喜欢
    • 2015-09-12
    • 2010-09-08
    • 2011-07-24
    • 2014-08-06
    • 2021-09-26
    • 1970-01-01
    相关资源
    最近更新 更多