LoginSignup
3
3

More than 5 years have passed since last update.

boost::units : 単位付きの quantity 型と無次元数の係数の積を簡単に記述する方法

Last updated at Posted at 2016-03-26

状況

  1. 円周 = π × 半径 × 2 と算数で習う。
  2. 地球の半径は 6.378'137e+6 m と WGS84 に書いてある。
  3. 地球の赤道の長さは?
#include <boost/units/systems/si.hpp> 
#include <boost/math/constants/constants.hpp>
#include <boost/units/io.hpp>
#include <iostream>

namespace some_app
{
  using namespace boost::units;
  using namespace boost::units::si;

  using float_type = long double;
  using length_type = quantity< length, float_type >;

  /// @brief π
  constexpr auto pi = boost::math::constants::pi< float_type >();

  /// @brief 地球の半径(ref. WGS84)
  const length_type earth_equatorial_radius = 6.378'137e+6 * meters;

  /// @brief 地球の赤道の長さ
  const length_type earth_equator_length    = pi * earth_equatorial_radius * 2; // <-- Oops! Compile Error!!
}

int main()
{
  std::cout << some_app::earth_equator_length;
}

Oops! Compile Error!!

prog.cc:29:76: error: no match for 'operator*' (operand types are 'boost::units::multiply_typeof_helper<long double, boost::units::quantity<boost::units::unit<boost::units::list<boost::units::dim<boost::units::length_base_dimension, boost::units::static_rational<1l> >, boost::units::dimensionless_type>, boost::units::homogeneous_system<boost::units::list<boost::units::si::meter_base_unit, boost::units::list<boost::units::scaled_base_unit<boost::units::cgs::gram_base_unit, boost::units::scale<10l, boost::units::static_rational<3l> > >, boost::units::list<boost::units::si::second_base_unit, boost::units::list<boost::units::si::ampere_base_unit, boost::units::list<boost::units::si::kelvin_base_unit, boost::units::list<boost::units::si::mole_base_unit, boost::units::list<boost::units::si::candela_base_unit, boost::units::list<boost::units::angle::radian_base_unit, boost::units::list<boost::units::angle::steradian_base_unit, boost::units::dimensionless_type> > > > > > > > > > >, long double> >::type {aka boost::units::quantity<boost::units::unit<boost::units::list<boost::units::dim<boost::units::length_base_dimension, boost::units::static_rational<1l> >, boost::units::dimensionless_type>, boost::units::homogeneous_system<boost::units::list<boost::units::si::meter_base_unit, boost::units::list<boost::units::scaled_base_unit<boost::units::cgs::gram_base_unit, boost::units::scale<10l, boost::units::static_rational<3l> > >, boost::units::list<boost::units::si::second_base_unit, boost::units::list<boost::units::si::ampere_base_unit, boost::units::list<boost::units::si::kelvin_base_unit, boost::units::list<boost::units::si::mole_base_unit, boost::units::list<boost::units::si::candela_base_unit, boost::units::list<boost::units::angle::radian_base_unit, boost::units::list<boost::units::angle::steradian_base_unit, boost::units::dimensionless_type> > > > > > > > > > >, long double>}' and 'int')
   const length_type earth_equator_length    = pi * earth_equatorial_radius * 2; // <-- Oops! Compile Error!!
                                                                            ^

方法

仕込み

  /// @brief 無次元数 × 単位付き型
  template<typename UNIT, typename IN_BASE, typename IN_FACTOR > 
  inline auto operator*( const IN_FACTOR& in_factor, const quantity< UNIT, IN_BASE >& in_base )
  { return static_cast< IN_BASE >( in_factor ) * in_base; }

  /// @brief 単位付き型 × 無次元数
  template<typename UNIT, typename IN_FACTOR, typename IN_BASE > 
  inline auto operator*( const quantity< UNIT, IN_BASE >& in_base, const IN_FACTOR& in_factor )
  { return in_base * static_cast< IN_BASE >( in_factor ); }

期待動作するソース全体

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

namespace some_app
{
  using namespace boost::units;
  using namespace boost::units::si;

  using float_type = long double;
  using length_type = quantity< length, float_type >;

  /// @brief 無次元数 × 単位付き型
  template<typename UNIT, typename IN_BASE, typename IN_FACTOR > 
  inline auto operator*( const IN_FACTOR& in_factor, const quantity< UNIT, IN_BASE >& in_base )
  { return static_cast< IN_BASE >( in_factor ) * in_base; }

  /// @brief 単位付き型 × 無次元数
  template<typename UNIT, typename IN_FACTOR, typename IN_BASE > 
  inline auto operator*( const quantity< UNIT, IN_BASE >& in_base, const IN_FACTOR& in_factor )
  { return in_base * static_cast< IN_BASE >( in_factor ); }

  /// @brief π
  constexpr auto pi = boost::math::constants::pi< float_type >();

  /// @brief 地球の半径(ref. WGS84)
  const length_type earth_equatorial_radius = 6.378'137e+6 * meters;

  /// @brief 地球の赤道の長さ
  const length_type earth_equator_length    = pi * earth_equatorial_radius * 2; // <-- Oops! Compile Error!!
}

int main()
{
  std::cout << some_app::earth_equator_length;
}

出力例

4.0075e+07 m

wandbox

Reference

3
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
3