1

読ん<ratio>でいて、偶発的な変換エラーから保護<chrono>するタイプを想像しようとしました。Length

これは私が得たものです:

#include <iostream>
#include <ratio>
using namespace std;

template<typename Scale>
struct Length  {
  long long val_;
  Length(long long val) : val_{val} {}
  Length() = default;
  Length(const Length&) = default;
  Length& operator=(const Length&) = default;
  // conversion
  template<typename Scale2>
  Length(const Length<Scale2> &other)
    : val_{ other.val_*(Scale2::num*Scale::den)/(Scale2::den*Scale::num) }
  { }
  // access
  long long value() const { return val_; }
}; 
typedef Length<ratio<1>> m;
typedef Length<kilo> km;
typedef Length<milli> mm;
typedef Length<ratio<1000,1094>> yard;

このように使用するには

int main() {
  km len_km = 300;
  mm len_mm = len_km;
  cout << " millimeter:" << len_mm.value() << endl;
  cout << " m:" << m{len_km}.value() << endl;
  cout << " yd:" << yard{len_km}.value() << endl;
}

そして今、すべての+and*操作を追加して、本当に快適にすることができました... :-)

私は疑問に思う:

  • とにかくで定義する算術機能へのより簡単なアクセスdurationはありますか? それらを使用して労力を軽減できますか?time_point<chrono>Length
  • コンパイル時の定数は、変換コンストラクター(Scale2::num*Scale::den)/(Scale2::den*Scale::num)(分数/アンダーフロー?) で危険に思えますが、より良いメタプログラミングの方法を理解できません。ここに何かヒントはありますか?
4

2 に答える 2

2
  • とにかくで 定義する 算術機能へのより簡単なアクセスdurationはありますか? それらを使用して労力を軽減できますか?time_point<chrono>Length

「混合モード」の演算と比較ではcommon_type<T1, T2>::type、戻り値の型を定義するために利用できます。は、Period1 と Period2 の最大公約数になるようにduration特化しています。ここで、Period1 と Period2 は、算術演算または比較演算に関与する 2 つの です。次のように使用できます。common_typeratio

template <typename Scale1, typename Scale2>
  typename std::common_type<Length<Scale1>, Length<Scale2>>::type
  operator+(Length<Scale1> x, Length<Scale2> y);

ratio残念ながら、コンパイル時に 2 の最大公約数を取得する方法を再発明する必要があります。unsigned long long のコンパイル時の gcd および lcm メタ関数から始めます。

common_typeうーん... または、 の専門化を のためにすでに行ったものに基づいて行うことができるかもしれませんdurationduration結果のperiodを のスケール係数として再解釈できますLength。私はこれをプロトタイプとして作成したのではなく、単なるアイデアです。

  • コンパイル時の定数 は、変換コンストラクター(Scale2::num*Scale::den)/(Scale2::den*Scale::num)(分数/アンダーフロー?) で危険に思えますが、より良いメタプログラミングの方法を理解できません。ここに何かヒントはありますか?

同意した。 durationこれを次の方法で処理します。

template <class Rep2, class Period2>
  constexpr duration(const duration<Rep2, Period2>& d);

備考:このコンストラクターは、treat_as_floating_point<rep>::valueが true であるか、両方 ratio_divide<Period2, period>::denが 1 でtreat_as_floating_point<Rep2>::valueあり false でない限り、オーバーロードの解決に参加しません。[注:この要件により、整数ベースの期間タイプ間で変換する際の暗黙的な切り捨てエラーが防止されます。このような構造は、デュレーションの値について混乱を招きやすいものです。—エンドノート]

つまり、変換が正確な場合にのみ存在するように変換コンストラクターenable_ifが必要です(整数型に基づいて長さを設定する場合)。Length変換を正確に行うには、変換係数(Scale2::num*Scale::den)/(Scale2::den*Scale::num)を除算なしで計算できる必要があります (1 による除算を除く)。を使用ratio_divideしてこの除算を行うと、結果の分母は 1 になる必要があります (正確な変換の場合)。

enable_if<ratio_divide<Scale2, Scale1>::type::den == 1, ...>

これは学習のための素晴らしいプロジェクトですratio!楽しむ!:-)

于 2011-05-31T12:56:40.037 に答える
1

整数型を使用して物理量を表します。これは、人々が通常望んでいることではありません。整数型を主張する場合は、少なくとも乗算と除算を正しい順序で実行します。つまり、最初にすべての乗算を行い、次に除算を行います (100*(255/256) と (100*255)/256 を比較してください)。

関連する注意事項として、長さを長さで掛けると、長さではなく面積が得られることに注意してください。これを考慮した実際のライブラリが存在します。たとえば、siunitsを参照してください。

于 2011-05-31T09:18:25.233 に答える