2017-11-13 5 views
1

現在、タイプシステムを活用して、パラメータの曖昧さを解消し、関数のコールサイトの可読性を向上させるための推奨方法は何ですか?簡単な例では、それはパラメータがあるtotal(10, 2)手段のような呼び出し、すなわち、この場合、どの(バグを取得しないものを正確に伝えるのは難しいですスカラーと強制コールサイトの可読性?

int total(int price, int amount) { 
    return price * total; 
} 

である、なぜなら可換性のあなたが台無し順序を場合乗算の)。

基本的に、あなたはすぐに何か行うことができます。同時に、コンパイラとして、ゼロコストの抽象化でありながら、発信者は、引数の順序をミックスするためにこれは、それは非常に困難になるだろう

enum class ScalarTypeTag { PriceTag, AmountTag, TotalTag}; 

template<typename T, ScalarTypeTag K> 
struct ScalarWrapper { 
    explicit ScalarWrapper(T value) : value_{value} {} 
    T value_; 
}; 

using Price = ScalarWrapper<int, ScalarTypeTag::PriceTag>; 
using Amount = ScalarWrapper<int, ScalarTypeTag::PriceTag>; 
using Total = ScalarWrapper<int, ScalarTypeTag::TotalTag>; 

Total ComputeTotal(Price p, Amount n) { 
    return Total(p.value_ * n.value_); 
} 

を意志ラッピングタイプを最適化します。私は基本的にこれを行う方法に興味があります:

  1. ユーザーが必要とする余分なコードを最小限に抑えます。

  2. (ミスなし)新しいタイプを追加することが些細な作り

  3. (単に基礎となるタイプでタイプを置き換えると比較して)ゼロコストの抽象化です。上記の例では

、私は意図的にコピー&ペーストした後AmountTagに金額上のタグを変更し忘れることでバグを導入しましたので、金額は実際の価格と同じタイプであるので、我々は誤って混乱まだ可能性パラメータの順序を上げるとコンパイラはそれをキャッチしません。このような塊茎の可能性を最小限に抑えることが望ましいでしょう。

言い換えれば、この構造の有用性を最大限に引き出し、煩わしさを最小限に抑える方法は?

更新:もう1つの問題は、この実装では(おそらくチェックしていない)std :: vectorのコピーがループの代わりにmemcpyに最適化されてしまうことを防ぐことができるということです。完全にゼロコストである。

+0

これは[boost-units](http://www.boost.org/doc/libs/1_65_0/doc/html/boost_units.html)のタスクのようです。 – rodrigo

答えて

0
struct tag_t {constexpr tag_t(){}}; 

inline constexpr tag_t price{} 
inline constexpr tag_t amount{}; 
inline constexpr tag_t total{}; 

template<class T, tag_t const* tag> 
struct scalar_t { 
    T t; 
    constexpr explicit scalar_t(T tin):t(std::move(tin)) {} 
    constexpr scalar_t(scalar_t const&) = default; 
    constexpr scalar_t(scalar_t &&) = default; 
    constexpr scalar_t& operator=(scalar_t const&) = default; 
    constexpr scalar_t& operator=(scalar_t &&) = default; 
    constexpr scalar_t() = default; 
    constexpr ~scalar_t() = default; 
}; 

template<auto x, tag_t const* tag > 
constexpr auto scalar = scalar_t<std::decay_t<decltype(x)>, tag>(x); 

template<tag_t const* tag> 
using iscalar_t = scalar_t<int, tag>; 

scalar_t<int, &total> ComputeTotal(scalar_t<int, &price> p, scalar_t<int, &amount> n) { 
    return scalar_t<int, &total>(p.t * n.t); 
} 

発信者は

int x = 33; 
auto total = ComputeTotal(scalar<7, &price>, iscalar_t<&amount>(x)); 

を行うと、キャストでコンパイル時の値または実行時の値を渡すことができます。

私たちはタイプエイリアスを実行しません。代わりに、タグのタグへのポインタを使用します。誰でも新しいスカラータグを作成することができ、そのconstexprアドレスはそのアイデンティティです。

これにより、分散スカラー型生成が可能になります。

関連する問題