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

# 状況

## 例

1. `円周 ＝ π × 半径 × 2` と算数で習う。
2. 地球の半径は `6.378'137e+6` m と WGS84 に書いてある。
3. 地球の赤道の長さは？

```cpp
#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!!
                                                                            ^
```

# 方法

## 仕込み

```cpp
  /// @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 ); }
```

## 期待動作するソース全体

```cpp
#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

- http://melpon.org/wandbox/permlink/XrcLOz6GO9LIsUwD

# Reference

- http://stackoverflow.com/questions/12903186/multiplying-a-scalar-by-a-boost-units-quantity-automatic-type-conversion-issues
- http://www.linz.govt.nz/data/geodetic-system/datums-projections-heights/geodetic-datums/world-geodetic-system-1984-wgs84
- http://mathworld.wolfram.com/Circle.html