2013-10-03 38 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

真是一个伟大的答案!谢谢。 –