使用增强单位

时间:2016-07-08 06:24:50

标签: c++ templates boost boost-units

我试图弄清楚boost-unit是否可以在我的某个项目中使用。对于大部分功能,我非常满意。但有一个我自己无法做到的功能。

特别是,我正在寻找一种易于使用的功能,它可以让我获得给定数量的某个基本单位的力量。它以某种方式与pow功能相反。实际上,io.hpp实现了类似的东西,但我既不想复制并粘贴其中的所有内容,也不想深入研究这个模板代码。

下面描述的getPow函数是否有简单的解决方法?

#include <boost/units/systems/si.hpp>
#include <boost/units/io.hpp>
#include <iostream>

using namespace boost::units;

template<typename U, typename V> 
int getPow(quantity<U>& q, V) {
    int ret = 0;
    // What do I have to write here?
    return ret;
}

int main(int argc, char** args) {
    auto q = 1.*si::meter*si::meter/si::second;
    std::cout << q << std::endl;
    std::cout << getPow(q, si::meter) << std::endl; // Should output 2
    std::cout << getPow(q, si::second) << std::endl; // Should output -1
}

1 个答案:

答案 0 :(得分:1)

以下代码实现了您的需求。我以前没有使用过boost :: units,所以可能有更惯用的方法来解决这个问题。

#include <type_traits>
#include <iostream>

#include <boost/mpl/at.hpp>
#include <boost/mpl/is_sequence.hpp>
#include <boost/mpl/find_if.hpp>

#include <boost/units/systems/si.hpp>
#include <boost/units/io.hpp>

using namespace boost::units;

template <typename T>
using get_dimension_t = typename T::unit_type::dimension_type;

template<typename T>
struct get_tag
{
    using type = typename T::tag_type;
};

template <typename T>
using get_tag_t = typename T::tag_type;

template< class ... > using void_t = void;

template<typename U, typename V> 
struct Exponent
{
    template <typename Dim, typename Enable = void>
    struct get
    {
        static constexpr int value = 0;
    };

    template <typename Dim>
    struct get<Dim, void_t<typename Dim::value_type>>
    {
         using Value = typename Dim::value_type;
         static constexpr int value = Value::Numerator / Value::Denominator;
    };

    using dimension_V = get_dimension_t<V>;

    using tag_to_search_for = typename get_tag<typename boost::mpl::at_c<dimension_V, 0>::type>::type;

    using dimension_U = get_dimension_t<U>;

    using iter = typename boost::mpl::find_if<dimension_U, std::is_same<get_tag<boost::mpl::_1>, tag_to_search_for> >::type;

    using Dim = typename boost::mpl::deref<iter>::type;

    constexpr static int value = get<Dim>::value;

};

template <typename U, typename V>
constexpr auto getExponent(U&& u, V&& v)
{
    return Exponent<std::decay_t<U>, std::decay_t<V>>::value;
}


int main(int argc, char** args) {
    auto q = 1.*si::meter*si::meter/si::second;
    std::cout << q << std::endl;
    std::cout << getExponent(q, si::meter) << std::endl; // Should output 2
    std::cout << getExponent(q, si::second) << std::endl; // Should output -1

    auto r = 1.*si::radian;
    std::cout << getExponent(r, si::meter) << std::endl; // Should output 0
}

live example