2017-02-10 3 views
1

オーバーフロー/アンダーフローのエラーを検出するのに役立つ算術ラッパーを作成しましたが、プロセスでかなり重大な問題があります。テンプレートの戻り値の型を変更すると、オーバーロードの解像度に影響があるように見えます

いくつかのオーバーロードされた演算子を介してオーバーフローを引き起こす可能性のあるすべてのものを処理し、他のすべてのものについては潜在的な型に暗黙的にキャスト可能なクラスがあるとします。この例では、バイナリプラス演算子が含まれています。これは、(基本的には、それらのすべての可能な1)(ここでそれを貼り付けている間、私は何かを逃さなかった場合)、罰金コンパイルし、このような状況では期待通りに を働く

template<typename T_> 
class Wrapper 
{ 
    public: 
    Wrapper(T_ val_) : m_value(val_) { } // converting constructor 
    operator T_(void) const { return m_value; } // underlying type conversion 
    // some other methods 

    // binary plus operators: 
    template<typename U_> 
    const Wrapper<decltype(T_() + U_())> operator +(U_ val_) const 
    { 
     // supposed to handle 'Wrapped + Unwrapped' case 
     return m_value + val_; 
    } 
    template<typename U_> 
    const Wrapper<decltype(T_() + U_())> operator +(Wrapper<U_> other_) const 
    { 
     // supposed to handle 'Wrapped + Wrapped' case 
     return m_value + other_.m_value; 
    } 

    template<typename U0_, typename U1_> 
    friend const Wrapper<decltype(U0_() + U1_())> operator +(U0_ val_, Wrapper<U1_> wrapper_) 
    { 
     // supposed to handle 'Unwrapped + Wrapped' case 
     return val_ + wrapper_.m_value; 
    } 

    private: 
    T_ m_value; 
}; 

:しかし

Wrapper<int> val = 3.14f; 
::std::cout << val + 42 << ::std::endl; // Wrapped + Unwrapped 
::std::cout << 42 + val << ::std::endl; // Unwrapped + Wrapped 
::std::cout << val + val << ::std::endl; // Wrapped + Wrapped 

、私は「+ラップアンラップ」または、次のように例えば「ラップアンラップ+」のいずれかのdecltype(...)一部のエイリアスを作成しようとするたびに:

template<typename T0_, typename T1_> 
struct Result 
{ 
    typedef decltype(T0_() + T1_()) Type; 
}; 

template<typename T_> 
class Wrapper 
{ 
    //... 
    template<typename U_> 
    const Wrapper<typename Result<T_, U_>::Type> operator +(U_ val_) const 
    //... 
    template<typename U0_, typename U1_> 
    friend const Wrapper<typename Result<U0_, U1_>::Type> operator +(U0_ val_, Wrapper<U1_> wrapper_) 
    //... 
}; 

「ラップされた+ラップされた」例は、望ましくない変形に向かって過負荷の解像度が変化するように見えるため、コンパイルしたくありません。 Wrapper<int>の既定のコンストラクタが使用できないというエラーがスローされ、問題のケースを適切に処理するのに適していない「ラップ+アンラップ」または「ラップ解除+ラップ」のいずれかを使用しようとしています。

戻り値の型が変わると、オーバーロードの解決動作が変化するように見えます。この問題に関するアドバイスをいただければ幸いです。

+1

を。潜在的に無効な式が 'Result'の定義に移され、直後のコンテキストの外に移動されたためです。 –

+0

このような状況で過負荷を解消するためには、「ラップされた+ラップされた」変種がより適切なものと見なされることを最初から間違っていました。あなたは答えのためにお会いしましょう。 – so100217

+1

(部分的な順序付けなどのために)うまく過負荷になるかもしれませんが、そこにも到達しません。候補のセットを形成しようとすると、ハードエラーが発生します。 –

答えて

1

ここではオーバーロードの解決がどのように機能するかを大まかです:候補関数や関数テンプレートを見つけるため

  1. 名のルックアップを。
  2. 各関数テンプレートのテンプレート引数を控除し、テンプレートに推論引数を代入して、単一の関数テンプレート特殊化を候補として生成します。控除に失敗した関数テンプレート(置換失敗を含む)をすべて破棄します。
  3. 候補を比較してください。最高のものを選ぶか、それがなければ文句を言う。

ステップ2で、ハードウェアエラーが発生した場合 - 関数テンプレートシグネチャの直後のコンテキスト外に無効な構造を作成すると、プログラムが不正な形式になります。ステップ3には行かない。エラーがなければ、ステップ3で候補者が選ばれなかったかどうかは問題ではない。

ここでは、decltype(T_() + U_())は本来は直接的な関係にありました。したがって、U_Wrapper<...>に推定され、署名に代入された場合、その式は不正ですが、エラーは直後のコンテキストにあるため、置換に失敗します。しかし、その式を別のクラステンプレートResultに移動すると、そのエラーは関数テンプレートのシグネチャの直後のコンテキストに存在しなくなるため、代わりにハードエラーになります。

エイリアステンプレート、表現を複数回繰り返し使用したくない場合は、次の望ましくない過負荷を離れSFINAE'dた

template<class T, class U> 
using result = decltype(T() + U()); 
+0

もう一度この有益な答えをありがとう。それは私が持っている問題を徹底的に説明します。私ができるだけ早く取り組んでいることを絶対に完了しなければならないので、テンプレートのすべての特徴を学ぶことができないのは非常にイライラします。 P.S:テンプレートエイリアシングについて知っていますが、srtuctはいくつかの追加の静的メソッドのためにあります。 – so100217

関連する問題