代码之家  ›  专栏  ›  技术社区  ›  hochl Michael Aaron Safyan

抑制由于常量为零而导致比较总是错误的警告

  •  0
  • hochl Michael Aaron Safyan  · 技术社区  · 6 年前

    我在一个本地项目中发现了此表单的代码:

    #include <iostream>
    
    const unsigned LOWER_LIMIT = 0;
    
    int main(int argc, char* argv[])
    {
        if (argc > 1) {
            unsigned a = atoi(argv[1]);
            if (a < LOWER_LIMIT) {
            // if (a - LOWER_LIMIT > a) {
                std::cerr << "lower\n";
                a = LOWER_LIMIT;
            }
        }
    }
    

    atoi() 部分仅用于 可运行性 g++ -Wall -Wextra :

    comparison of unsigned expression < 0 is always false
    

    if (a - LOWER_LIMIT > a) {
    

    使用无符号下溢。但对于某些人来说,这个解决方案有点难以理解。我找到了一个不同的解决方案:

    #pragma GCC diagnostic push
    #pragma GCC diagnostic ignored "-Wtype-limits"
    if (a < LOWER_LIMIT) {
    #pragma GCC diagnostic pop
    

    这是可行的,但我认为 GCC 这不是一个可移植的解决方案。

    有没有一种可移植的、通用的、易于理解的方法来避免这个警告,并且仍然能够让一些开发人员简单地更改常量,而不必知道发生比较的代码库的这一部分?

    我有一个模板解决方案,但感觉太过了:

    template<typename NumericTypeA, typename NumericTypeB>
    typename std::enable_if<std::is_unsigned<NumericTypeA>::value &&
                std::is_unsigned<NumericTypeB>::value, bool >::type
    is_smaller_than(NumericTypeA a, NumericTypeB b)
    {
        return (a - b > a);
    }
    
    template<typename NumericTypeA, typename NumericTypeB>
    typename std::enable_if<std::is_signed<NumericTypeA>::value &&
                std::is_signed<NumericTypeB>::value, bool >::type
    is_smaller_than(NumericTypeA a, NumericTypeB b)
    {
        return (a < b);
    }
    

    编辑2: 如果编译器检测到比较总是false,那么它是否有必要检查下面的语句并检测这是否正常(在响应中也建议)?

    if ((LOWER_LIMIT > 0) && (a < LOWER_LIMIT)) {
    

    3 回复  |  直到 6 年前
        1
  •  2
  •   Jarod42    6 年前

    if (std::less<>()(a, LOWER_LIMIT)) // extra function
    

    可能是使用模板过度使用:

    template <std::size_t Limit>
    struct DoesIfLess
    {
        template <typename F>
        void operator ()(std::size_t a, F&&f) {
            if (a < Limit) {
                std::forward<F>(f)();
            }
        }
    };
    
    template <>
    struct DoesIfLess<0>
    {
        template <typename F>
        void operator ()(std::size_t, F&&) {}
    };
    

    DoesIfLess<LOWER_LIMIT>(a, [&](){std::cerr << "lower\n"; a = LOWER_LIMIT; });
    

    或者用C++ 17

    if constexpr (LOWER_LIMIT != 0) {
        if (a < LOWER_LIMIT) {
            std::cerr << "lower\n";
            a = LOWER_LIMIT;
        }
    }
    
        2
  •  2
  •   eerorika    6 年前

    有便携式的pragma吗?

    #pragma 定义为实现定义。

    特别是警告选项在不同的编译器中差别很大。

    维护者不想。。。

    -isystem 替代选项 -I . 这种方式 不用担心 他们的 警告。

        3
  •  2
  •   François Andrieux    6 年前

    #include <iostream>
    
    const unsigned LOWER_LIMIT = 0;
    
    constexpr auto get_lower_limit() { return LOWER_LIMIT; }
    
    int main(int argc, char* argv[])
    {
        if (argc > 1) {
            unsigned a = atoi(argv[1]);
    
            if (a < get_lower_limit()) {
                std::cerr << "lower\n";
                a = LOWER_LIMIT;
            }
        }
    }