C++ Programming Language中的narrow_cast實現


在C++中,各種數值類型的轉化是C++編譯過程中警告的主要來源,但是,很多時候,我們需要使用各種數值類型,例如我們用數組的某一位表示大小為對應序號的值,這種情況下,經常會涉及多種數值類型。根據C++ Programming Language中的建議,在數值類型轉換時,使用narrow_cast來實現運行時安全,這里給出C++14版本的實現。

// there is no implicit conversion from Source to Target
template <typename Target, typename Source,
    typename = std::enable_if_t<
    !std::is_same<std::common_type_t<Target, Source>, std::decay_t<Target>>::value>>
    inline Target narrow_cast(Source v)
{
    static_assert(!std::is_reference<Target>::value, "The target couldn't be reference");
    static_assert(std::is_arithmetic<Source>::value, "The parameter of narrow_cast should be arithmetic");
    static_assert(std::is_arithmetic<Target>::value, "The return value of narrow_cast should be arithmetic");

    // using Target_U = std::remove_reference_t<Target>;
    // using Source_U = std::remove_reference_t<Source>;

    auto r = static_cast<Target>(v);
    if (static_cast<Source>(r) != v)
        throw std::runtime_error("narrow_cast<>() failed");
    return r;
}

// there is implicit conversion from Source to Target
template <typename Target, typename Source,
    typename = std::enable_if_t<
    std::is_same<std::common_type_t<Target, Source>, std::decay_t<Target>>::value>>
    inline constexpr std::remove_reference_t<Source> narrow_cast(Source v)
{
    static_assert(!std::is_reference<Target>::value, "The target couldn't be reference");
    static_assert(std::is_arithmetic<Source>::value, "The parameter of narrow_cast should be arithmetic");
    static_assert(std::is_arithmetic<Target>::value, "The return value of narrow_cast should be arithmetic");

    return static_cast<Target>(v);
}

下面給出,使用Catch寫的簡單測試用例:

#define CATCH_CONFIG_MAIN
#include "catch.hpp"
#include <cmath>

TEST_CASE("Test narrow_cast", "[narrow_cast]")
{
    int i = 10;
    long long j = 15;
    long long& k = j;
    REQUIRE(narrow_cast<long>(k) == 15);
    REQUIRE(narrow_cast<long>(i) == 10);
    long long very_big = pow(10, 12);
    bool exception = false;
    try
    {
        narrow_cast<long>(very_big) == very_big;
    }
    catch (const std::runtime_error& error)
    {
        exception = true;
    }
    REQUIRE(exception);
    //REQUIRE(narrow_cast<long&>(k) == 15);
    //REQUIRE(narrow_cast<long&>(i) == 10);
}

測試可知,在轉化的類型可以容納時,narrow_cast可以正常運行,如果narrow_cast轉化后的值與原值不同時,會拋出runtime_error的異常。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM