2013-10-03 37 views
2

我想用Boost.Units實現一個percent單位,以便無量綱數量(如比率)可以用百分比表示。我已成功實現了質量密度單位之間的轉換,但對於無量綱單位也是如此。這裏是我的代碼(假設using namespace boost::units;):使用Boost.Units定義百分比

// 
// gram per milliliter (g mL^-1) 
// 
namespace my { 
     struct gram_per_milliliter_base_unit : 
       base_unit<gram_per_milliliter_base_unit, mass_density_dimension, 1> 
     { 
       static std::string name() {return "gram per milliliter";} 
       static std::string symbol() {return "g mL^-1";} 
     }; 
     typedef gram_per_milliliter_base_unit::unit_type gram_per_milliliter_unit; 
     BOOST_UNITS_STATIC_CONSTANT(gram_per_milliliter, gram_per_milliliter_unit); 
     BOOST_UNITS_STATIC_CONSTANT(grams_per_milliliter, gram_per_milliliter_unit); 
} 
BOOST_UNITS_DEFINE_CONVERSION_FACTOR(
     my::gram_per_milliliter_base_unit, si::mass_density, double, 1.0e3 
); // 1 g mL^-1 == 1e3 kg m^-3 (SI unit) 
BOOST_UNITS_DEFAULT_CONVERSION(my::gram_per_milliliter_base_unit, si::mass_density); 

// 
// percentage (%) 
// 
namespace my { 
     struct percent_base_unit : 
       base_unit<percent_base_unit, dimensionless_type, 2> 
     { 
       static std::string name() {return "percent";} 
       static std::string symbol() {return "%";} 
     }; 
     typedef percent_base_unit::unit_type percent_unit; 
     BOOST_UNITS_STATIC_CONSTANT(percent, percent_unit); 
} 
BOOST_UNITS_DEFINE_CONVERSION_FACTOR(
     my::percent_base_unit, si::dimensionless, double, 1.0e-2 
); // 1 % == 1e-2 (SI dimensionless unit) 
BOOST_UNITS_DEFAULT_CONVERSION(my::percent_base_unit, si::dimensionless); 

的「每毫升克」節按預期工作:我可以編譯這段代碼(假設using namespace my;以及):

quantity<gram_per_milliliter_unit> q1my(3*grams_per_milliliter); 
quantity<si::mass_density> q1si(q1my); 
quantity<gram_per_milliliter_unit> q1back(q1si); 

但接下來的失敗以編譯兩次轉換:

quantity<percent_unit> q2my(3*percent); 
quantity<si::dimensionless> q2si(q2my); 
quantity<percent_unit> q2back(q2si); 

G ++輸出:no matching function for call to 'conversion_factor(..., ...)'

這是否與dimensionless_type似乎是類型列表結束的標記相關?

任何幫助或建議將不勝感激。謝謝。

回答

4

這與這樣一個事實有關:dimensionless_type似乎是類型列表結束的標記?

的排序。 dimensionless_type隱含地包含在每個測量系統中,並且以相同的方式從它們中提取,參見boost/units/dimensionless_units.hpp

在你的「百分比」的例子,認爲你的新的測量系統將是,如何你按照通常的壓單元規則指定:

namespace my { 
    ... // define your own unit tag types 
    typedef make_system</* your system's units with dimensions*/>::type system; 
    ... // unit typedefs, consts, etc. 
} 

所以,如果你說你的百分比將是無量綱的,但與原來的無量綱不同,你違抗上述概念。因此,您無法在系統中定義2個無量綱維度。

任何幫助或建議將不勝感激。

我看到三個選項,在這裏:

  1. 覆蓋底層的數量型和接受百分比或在構造函數正規號碼。 見http://www.boost.org/doc/libs/release/doc/html/boost_units/Examples.html#boost_units.Examples.UDTExample

  2. 如果你想以百分比顯示的東西,你可以嘗試使用自動縮放功能(從未做過它自己,但有還有一個例子 - http://www.boost.org/doc/libs/release/doc/html/boost_units/Examples.html#boost_units.Examples.autoscale)。

  3. 您可以創建一個特殊的自定義維度「百分比」,並明確地轉換爲百分比數量。這可能與您最初的意圖最接近,但自動轉換並不總是會發生,因爲該庫不是爲「無量綱量的空間分析」而設計的。你可以看到結果是如何醜陋的是,如果你試圖強制系統進入自動轉換:

    // 
    // percentage (%) 
    // 
    namespace my { 
        struct percent_base_dimension : 
         base_dimension<percent_base_dimension, 1> {}; 
        typedef percent_base_dimension::dimension_type percent_type; 
    
        struct percent_base_unit : 
         base_unit<percent_base_unit, percent_type, 1> 
        { 
         static std::string name() {return "percent";} 
         static std::string symbol() {return "%";} 
        }; 
        typedef make_system<percent_base_unit>::type system; 
        typedef percent_base_unit::unit_type percent_unit; 
        BOOST_UNITS_STATIC_CONSTANT(percent, percent_unit); 
    } 
    
    namespace boost { namespace units { 
    
    template<class T0, class T1> 
    struct conversion_helper<quantity<my::percent_unit, T0>, quantity<si::dimensionless, T1> > 
    { 
        static quantity<si::dimensionless, T1> convert(const quantity<my::percent_unit, T0>& source) 
        { 
         return(quantity<si::dimensionless, T1>::from_value(1e-2 * source.value())); 
        } 
    }; 
    
    template<class T0, class T1> 
    struct conversion_helper<quantity<si::dimensionless, T0>, quantity<my::percent_unit, T1> > 
    { 
        static quantity<my::percent_unit, T1> convert(const quantity<si::dimensionless, T0>& source) 
        { 
         return(quantity<my::percent_unit, T1>::from_value(1e+2 * source.value())); 
        } 
    }; 
    
    } } 
    
    int main() 
    { 
        using namespace my; 
    
        quantity<percent_unit> q2my(3*percent); 
    
        //quantity<si::dimensionless> q2si(q2my); 
        //The converter won't be picked up due to an explicit disable_if in quantity.hpp: 
        // typename boost::disable_if<detail::is_dimensionless_system<System2> >::type* = 0 
        //so we manually force the conversion here: 
        auto conv = conversion_helper<quantity<percent_unit>, quantity<si::dimensionless> >::convert; 
        quantity<si::dimensionless> q2si(conv(q2my)); 
    
        quantity<percent_unit> q2back(q2si); 
    
        std::cout 
         << "q2my: " << q2my << std::endl 
         << "q2si: " << q2si << std::endl 
         << "q2back: " << q2back << std::endl 
         ; 
    } 
    

    所以這是一個好主意,做手工,像

    namespace my { 
        template<class Y> 
        quantity<si::dimensionless, Y> units(const quantity<percent_unit, Y>& source) 
        { 
         return(quantity<si::dimensionless, Y>::from_value(1e-2 * source.value())); 
        } 
    
        template<class Y> 
        quantity<percent_unit, Y> percentage(const quantity<si::dimensionless, Y>& source) 
        { 
         return(quantity<percent_unit, Y>::from_value(1e+2 * source.value())); 
        } 
    
    } 
    
    int main() 
    { 
        using namespace my; 
    
        quantity<percent_unit> q2my(3*percent); 
        quantity<si::dimensionless> q2si(my::units(q2my)); 
        quantity<percent_unit> q2back(my::percentage(q2si)); 
    
        std::cout 
         << "q2my: " << q2my << std::endl 
         << "q2si: " << q2si << std::endl 
         << "q2back: " << q2back << std::endl 
         ; 
    } 
    

    ,或者更好的,使用類型檢查的好處(所以你只能犯了一個錯誤,在轉換系數這裏):

    template<class Y> 
    quantity<si::dimensionless, Y> units(const quantity<percent_unit, Y>& source) 
    { 
        return quantity<si::dimensionless, Y>(1e-2 * source/percent); 
    } 
    
    template<class Y> 
    quantity<percent_unit, Y> percentage(const quantity<si::dimensionless, Y>& source) 
    { 
        return quantity<percent_unit, Y>(1e+2 * source * percent); 
    } 
    
+0

真是一個偉大的答案!謝謝。 –