nholthaus / units

a compile-time, header-only, dimensional analysis and unit conversion library built on c++14 with no dependencies.
http://nholthaus.github.io/units/
MIT License
955 stars 135 forks source link

C4127 Warnings on /W4 #273

Open krofik opened 3 years ago

krofik commented 3 years ago

On MSVC with /W4 I am getting 27 warnings of type C4127 on lines 2215 to 2258 about that all these if-statements could be constant expression.

deleoDev91 commented 3 years ago

Hi, the warning is telling you that the result of all theese if-statements could be resolved in compile time, so the compiler is encouriging us to use different strategies to avoid expending time in checking conditions in runtine, in case the compiler doesnt perform any unfolding. In my case, I silenced the warning using SFINAE techniques. Just substitute the code on lines 2209 to 2261:

    template<class Units, typename T, template<typename> class NonLinearScale>
    inline std::ostream& operator<<(std::ostream& os, const unit_t<Units, T, NonLinearScale>& obj) noexcept
    {
        using BaseUnits = unit<std::ratio<1>, typename traits::unit_traits<Units>::base_unit_type>;
        os << convert<Units, BaseUnits>(obj());
        if (traits::unit_traits<Units>::base_unit_type::meter_ratio::num != 0) { os << " m"; }
        if (traits::unit_traits<Units>::base_unit_type::meter_ratio::num != 0 &&
            traits::unit_traits<Units>::base_unit_type::meter_ratio::num != 1) { os << "^" << traits::unit_traits<Units>::base_unit_type::meter_ratio::num; }
        if (traits::unit_traits<Units>::base_unit_type::meter_ratio::den != 1) { os << "/"   << traits::unit_traits<Units>::base_unit_type::meter_ratio::den; }

        if (traits::unit_traits<Units>::base_unit_type::kilogram_ratio::num != 0) { os << " kg"; }
        if (traits::unit_traits<Units>::base_unit_type::kilogram_ratio::num != 0 &&
            traits::unit_traits<Units>::base_unit_type::kilogram_ratio::num != 1) { os << "^" << traits::unit_traits<Units>::base_unit_type::kilogram_ratio::num; }
        if (traits::unit_traits<Units>::base_unit_type::kilogram_ratio::den != 1) { os << "/" << traits::unit_traits<Units>::base_unit_type::kilogram_ratio::den; }

        if (traits::unit_traits<Units>::base_unit_type::second_ratio::num != 0) { os << " s"; }
        if (traits::unit_traits<Units>::base_unit_type::second_ratio::num != 0 &&
            traits::unit_traits<Units>::base_unit_type::second_ratio::num != 1) { os << "^" << traits::unit_traits<Units>::base_unit_type::second_ratio::num; }
        if (traits::unit_traits<Units>::base_unit_type::second_ratio::den != 1) { os << "/" << traits::unit_traits<Units>::base_unit_type::second_ratio::den; }

        if (traits::unit_traits<Units>::base_unit_type::ampere_ratio::num != 0) { os << " A"; }
        if (traits::unit_traits<Units>::base_unit_type::ampere_ratio::num != 0 &&
            traits::unit_traits<Units>::base_unit_type::ampere_ratio::num != 1) { os << "^" << traits::unit_traits<Units>::base_unit_type::ampere_ratio::num; }
        if (traits::unit_traits<Units>::base_unit_type::ampere_ratio::den != 1) { os << "/" << traits::unit_traits<Units>::base_unit_type::ampere_ratio::den; }

        if (traits::unit_traits<Units>::base_unit_type::kelvin_ratio::num != 0) { os << " K"; }
        if (traits::unit_traits<Units>::base_unit_type::kelvin_ratio::num != 0 &&
            traits::unit_traits<Units>::base_unit_type::kelvin_ratio::num != 1) { os << "^" << traits::unit_traits<Units>::base_unit_type::kelvin_ratio::num; }
        if (traits::unit_traits<Units>::base_unit_type::kelvin_ratio::den != 1) { os << "/" << traits::unit_traits<Units>::base_unit_type::kelvin_ratio::den; }

        if (traits::unit_traits<Units>::base_unit_type::mole_ratio::num != 0) { os << " mol"; }
        if (traits::unit_traits<Units>::base_unit_type::mole_ratio::num != 0 &&
            traits::unit_traits<Units>::base_unit_type::mole_ratio::num != 1) { os << "^" << traits::unit_traits<Units>::base_unit_type::mole_ratio::num; }
        if (traits::unit_traits<Units>::base_unit_type::mole_ratio::den != 1) { os << "/" << traits::unit_traits<Units>::base_unit_type::mole_ratio::den; }

        if (traits::unit_traits<Units>::base_unit_type::candela_ratio::num != 0) { os << " cd"; }
        if (traits::unit_traits<Units>::base_unit_type::candela_ratio::num != 0 &&
            traits::unit_traits<Units>::base_unit_type::candela_ratio::num != 1) { os << "^" << traits::unit_traits<Units>::base_unit_type::candela_ratio::num; }
        if (traits::unit_traits<Units>::base_unit_type::candela_ratio::den != 1) { os << "/" << traits::unit_traits<Units>::base_unit_type::candela_ratio::den; }

        if (traits::unit_traits<Units>::base_unit_type::radian_ratio::num != 0) { os << " rad"; }
        if (traits::unit_traits<Units>::base_unit_type::radian_ratio::num != 0 &&
            traits::unit_traits<Units>::base_unit_type::radian_ratio::num != 1) { os << "^" << traits::unit_traits<Units>::base_unit_type::radian_ratio::num; }
        if (traits::unit_traits<Units>::base_unit_type::radian_ratio::den != 1) { os << "/" << traits::unit_traits<Units>::base_unit_type::radian_ratio::den; }

        if (traits::unit_traits<Units>::base_unit_type::byte_ratio::num != 0) { os << " b"; }
        if (traits::unit_traits<Units>::base_unit_type::byte_ratio::num != 0 &&
            traits::unit_traits<Units>::base_unit_type::byte_ratio::num != 1) { os << "^" << traits::unit_traits<Units>::base_unit_type::byte_ratio::num; }
        if (traits::unit_traits<Units>::base_unit_type::byte_ratio::den != 1) { os << "/" << traits::unit_traits<Units>::base_unit_type::byte_ratio::den; }

        return os;
    }

with this

    template<class Units>
    inline typename std::enable_if<
        Units::base_unit_type::meter_ratio::num != 0 &&
        Units::base_unit_type::meter_ratio::num != 1
    >::type
    print_num_value(std::ostream& os) noexcept
    {
        os << "^" << traits::unit_traits<Units>::base_unit_type::meter_ratio::num;
    }

    template<class Units>
    inline typename std::enable_if<
        Units::base_unit_type::kilogram_ratio::num != 0 &&
        Units::base_unit_type::kilogram_ratio::num != 1
    >::type
    print_num_value(std::ostream& os) noexcept
    {
        os << "^" << traits::unit_traits<Units>::base_unit_type::kilogram_ratio::num;
    }

    template<class Units>
    inline typename std::enable_if<
        Units::base_unit_type::second_ratio::num != 0 &&
        Units::base_unit_type::second_ratio::num != 1
    >::type
    print_num_value(std::ostream& os) noexcept
    {
        os << "^" << traits::unit_traits<Units>::base_unit_type::second_ratio::num;
    }

    template<class Units>
    inline typename std::enable_if<
        Units::base_unit_type::ampere_ratio::num != 0 &&
        Units::base_unit_type::ampere_ratio::num != 1
    >::type
    print_num_value(std::ostream& os) noexcept
    {
        os << "^" << traits::unit_traits<Units>::base_unit_type::ampere_ratio::num;
    }

    template<class Units>
    inline typename std::enable_if<
        Units::base_unit_type::kelvin_ratio::num != 0 &&
        Units::base_unit_type::kelvin_ratio::num != 1
    >::type
    print_num_value(std::ostream& os) noexcept
    {
        os << "^" << traits::unit_traits<Units>::base_unit_type::kelvin_ratio::num;
    }

    template<class Units>
    inline typename std::enable_if<
        Units::base_unit_type::mole_ratio::num != 0 &&
        Units::base_unit_type::mole_ratio::num != 1
    >::type
    print_num_value(std::ostream& os) noexcept
    {
        os << "^" << traits::unit_traits<Units>::base_unit_type::mole_ratio::num;
    }

    template<class Units>
    inline typename std::enable_if<
        Units::base_unit_type::candela_ratio::num != 0 &&
        Units::base_unit_type::candela_ratio::num != 1
    >::type
    print_num_value(std::ostream& os) noexcept
    {
        os << "^" << traits::unit_traits<Units>::base_unit_type::candela_ratio::num;
    }

    template<class Units>
    inline typename std::enable_if<
        Units::base_unit_type::radian_ratio::num != 0 &&
        Units::base_unit_type::radian_ratio::num != 1
    >::type
    print_num_value(std::ostream& os) noexcept
    {
        os << "^" << traits::unit_traits<Units>::base_unit_type::radian_ratio::num;
    }

    template<class Units>
    inline typename std::enable_if<
        Units::base_unit_type::byte_ratio::num != 0 &&
        Units::base_unit_type::byte_ratio::num != 1
    >::type
    print_num_value(std::ostream& os) noexcept
    {
        os << "^" << traits::unit_traits<Units>::base_unit_type::byte_ratio::num;
    }

    template<class Units>
    inline typename std::enable_if<
        (
            Units::base_unit_type::meter_ratio::num     == 0 ||
            Units::base_unit_type::meter_ratio::num     == 1 
        ) &&
        (
            Units::base_unit_type::kilogram_ratio::num  == 0 ||
            Units::base_unit_type::kilogram_ratio::num  == 1 
        ) &&
        (
            Units::base_unit_type::second_ratio::num    == 0 ||
            Units::base_unit_type::second_ratio::num    == 1
        ) &&
        (
            Units::base_unit_type::ampere_ratio::num    == 0 ||
            Units::base_unit_type::ampere_ratio::num    == 1 
        ) &&
        (
            Units::base_unit_type::kelvin_ratio::num    == 0 ||
            Units::base_unit_type::kelvin_ratio::num    == 1 
        ) &&
        (
            Units::base_unit_type::mole_ratio::num      == 0 ||
            Units::base_unit_type::mole_ratio::num      == 1
        ) &&
        (
            Units::base_unit_type::candela_ratio::num   == 0 ||
            Units::base_unit_type::candela_ratio::num   == 1
        ) &&
        (
            Units::base_unit_type::radian_ratio::num    == 0 ||
            Units::base_unit_type::radian_ratio::num    == 1 
        ) &&
        (
            Units::base_unit_type::byte_ratio::num      == 0 ||     
            Units::base_unit_type::byte_ratio::num      == 1
        )
    >::type
    print_num_value(std::ostream& os) noexcept
    {
        os;
    }

/****************print ratios****************/
    // length
    template<class Units>
    inline typename std::enable_if<Units::base_unit_type::meter_ratio::num != 0>::type
    print_num(std::ostream& os) noexcept
    {
        os << " m";
    }

    template<class Units>
    inline typename std::enable_if<Units::base_unit_type::meter_ratio::den != 1>::type
    print_den(std::ostream& os) noexcept
    {
        os << "/" << traits::unit_traits<Units>::base_unit_type::meter_ratio::den;
    }

    // mass
    template<class Units>
    inline typename std::enable_if<Units::base_unit_type::kilogram_ratio::num != 0>::type
    print_num(std::ostream& os) noexcept
    {
        os << " kg";
    }

    template<class Units>
    inline typename std::enable_if<Units::base_unit_type::kilogram_ratio::den != 1>::type
    print_den(std::ostream& os) noexcept
    {
        os << "/" << traits::unit_traits<Units>::base_unit_type::kilogram_ratio::den;
    }

    // time
    template<class Units>
    inline typename std::enable_if<Units::base_unit_type::second_ratio::num != 0>::type
    print_num(std::ostream& os) noexcept
    {
        os << " s";
    }

    template<class Units>
    inline typename std::enable_if<Units::base_unit_type::second_ratio::den != 1>::type
    print_den(std::ostream& os) noexcept
    {
        os << "/" << traits::unit_traits<Units>::base_unit_type::second_ratio::den;
    }

    // electric intesity
    template<class Units>
    inline typename std::enable_if<Units::base_unit_type::ampere_ratio::num != 0>::type
    print_num(std::ostream& os) noexcept
    {
        os << " A"; 
    }

    template<class Units>
    inline typename std::enable_if<Units::base_unit_type::ampere_ratio::den != 1>::type
    print_den(std::ostream& os) noexcept
    {
        os << "/" << traits::unit_traits<Units>::base_unit_type::ampere_ratio::den;
    }

    // temperature
    template<class Units>
    inline typename std::enable_if<Units::base_unit_type::kelvin_ratio::num != 0>::type
    print_num(std::ostream& os) noexcept
    {
        os << " K";
    }

    template<class Units>
    inline typename std::enable_if<Units::base_unit_type::kelvin_ratio::den != 1>::type
    print_den(std::ostream& os) noexcept
    {
        os << "/" << traits::unit_traits<Units>::base_unit_type::kelvin_ratio::den;
    }

    // moles
    template<class Units>
    inline typename std::enable_if<Units::base_unit_type::mole_ratio::num != 0>::type
    print_num(std::ostream& os) noexcept
    {
        os << " mol";
    }

    template<class Units>
    inline typename std::enable_if<Units::base_unit_type::mole_ratio::den != 1>::type
    print_den(std::ostream& os) noexcept
    {
        os << "/" << traits::unit_traits<Units>::base_unit_type::mole_ratio::den;
    }

    // luminosity
    template<class Units>
    inline typename std::enable_if<Units::base_unit_type::candela_ratio::num != 0>::type
    print_num(std::ostream& os) noexcept
    {
        os << " cd";
    }

    template<class Units>
    inline typename std::enable_if<Units::base_unit_type::candela_ratio::den != 1>::type
    print_den(std::ostream& os) noexcept
    {
        os << "/" << traits::unit_traits<Units>::base_unit_type::candela_ratio::den;
    }

    // angles
    template<class Units>
    inline typename std::enable_if<Units::base_unit_type::radian_ratio::num != 0>::type
    print_num(std::ostream& os) noexcept
    {
        os << " rad";
    }

    template<class Units>
    inline typename std::enable_if<Units::base_unit_type::radian_ratio::den != 1>::type
    print_den(std::ostream& os) noexcept
    {
        os << "/" << traits::unit_traits<Units>::base_unit_type::radian_ratio::den;
    }

    // bytes
    template<class Units>
    inline typename std::enable_if<Units::base_unit_type::byte_ratio::num != 0>::type
    print_num(std::ostream& os) noexcept
    {
        os << " b";
    }

    template<class Units>
    inline typename std::enable_if<Units::base_unit_type::byte_ratio::den != 1>::type
    print_den(std::ostream& os) noexcept
    {
        os << "/" << traits::unit_traits<Units>::base_unit_type::byte_ratio::den;
    }

    template<class Units>
    inline typename std::enable_if<
        Units::base_unit_type::byte_ratio::num      == 0 &&
        Units::base_unit_type::kilogram_ratio::num  == 0 &&
        Units::base_unit_type::second_ratio::num    == 0 &&
        Units::base_unit_type::ampere_ratio::num    == 0 &&
        Units::base_unit_type::kelvin_ratio::num    == 0 &&
        Units::base_unit_type::mole_ratio::num      == 0 &&
        Units::base_unit_type::candela_ratio::num   == 0 &&
        Units::base_unit_type::radian_ratio::num    == 0 &&
        Units::base_unit_type::byte_ratio::num      == 0
    >::type
    print_num(std::ostream& os) noexcept
    {
        os;
    }

    template<class Units>
    inline typename std::enable_if<
        Units::base_unit_type::byte_ratio::den      == 1 &&
        Units::base_unit_type::kilogram_ratio::den  == 1 &&
        Units::base_unit_type::second_ratio::den    == 1 &&
        Units::base_unit_type::ampere_ratio::den    == 1 &&
        Units::base_unit_type::kelvin_ratio::den    == 1 &&
        Units::base_unit_type::mole_ratio::den      == 1 &&
        Units::base_unit_type::candela_ratio::den   == 1 &&
        Units::base_unit_type::radian_ratio::den    == 1 &&
        Units::base_unit_type::byte_ratio::den      == 1
    >::type
    print_den(std::ostream& os) noexcept
    {
        os;
    }

    template<class Units, typename T, template<typename> class NonLinearScale>
    inline std::ostream& operator<<(std::ostream& os, const unit_t<Units, T, NonLinearScale>& obj) noexcept
    {
        using BaseUnits = unit<std::ratio<1>, typename traits::unit_traits<Units>::base_unit_type>;
        os << convert<Units, BaseUnits>(obj());

        print_num<Units>(os);
        print_num_value<Units>(os);
        print_den<Units>(os);

        return os;
    }

I havent tested yet but it should behave the same way, so it is up to you to use it or not. Of course, I included it in my code, so if i have further notice I'll post it

Guillaume227 commented 3 years ago

Facing the same problem, I replaced the if statements with if constexpr which did away with the warnings. Note that if-constexpr is a c++17 feature.