1

整数値をラップし、この値が常に有効な範囲内にあることを確認する C++ テンプレート クラスを作成しようとしているため、簡略化されたコードは次のようになります。

struct OutOfRangeError  
{ };  

template<int MIN, int MAX, typename TYPE>  
struct IntegerRange  
{  
    private:  
    TYPE mValue;  

    public:  
    IntegerRange(const TYPE value) : mValue(value)  
    {  
        if (MIN > value || value > MAX)  
        {  
            throw OutOfRangeError();  
        }  
    }  

    operator TYPE() const  
    {  
        return mValue;  
    }  
}  

前のコードは機能しますが、このクラスを使用する場合に少し欠点があります。以下にサンプルを示します。

typedef IntegerRange<0, 4, int> range1_t;  
typedef IntegerRange<0, 5, int> range2_t;  

range1_t a = 3;  
//range2_t b = a; // This does not work  
range2_t b = static_cast<int>(a); // This works OK  

したがって、異なる範囲間で値を割り当てるには、指定された TYPE に明示的にキャストする必要があります。この明示的なキャストを回避し、通常の整数であるため IntegerRange クラスを処理することを避けるための解決策が必要です。そのため、開発者は、クラスではなく通常の整数を扱っていると感じるはずです。

これを解決するために、私はさまざまなことを試しました。1 つの作業は、追加のコンストラクターとして次のものです。

template<typename RANGE_TYPE>  
IntegerRange(const RANGE_TYPE &value) :  
        mValue(static_cast<const TYPE>(value))  
{  
    if (MIN > mValue || mValue > MAX)  
    {  
        throw OutOfRangeError();  
    }  
}  

ただし、これが機能する場合でも、RANGE_TYPE は TYPE にキャストできる任意の型になる可能性があるため、あまり好きではなく、これを IntegerRange クラスのみに制限したいと考えています。IntegerRange クラスのみに制限するために、次のことを試しましたが、コンパイルされておらず、理由がわかりません。

template<int ARG_MIN, int ARG_MAX, typename ARG_TYPE>  
IntegerRange(const IntegerRange<ARG_MIN, ARG_MAX, typename ARG_TYPE> &value) :  
        mValue(static_cast<const TYPE>(value))  
{  
    if (MIN > value || value > MAX)  
    {  
        throw OutOfRangeError();  
    }  
}  

質問は 2 です:
* コードの最後の部分がコンパイルされない理由と、それをコンパイルするために何を変更する必要があるか。
* 行方不明の明示的なキャストを避けるほうがよい方法はありますか?

ありがとう

4

2 に答える 2

2

まず、POSIX数値定数として既に定義されている可能性があるため、テンプレート名として使用しないでください。ARG_MAX

typename次に、の 3 番目のテンプレート引数の を削除する必要がありますIntegerRange

IntegerRange(const IntegerRange<ARG_MIN, ARG_MAX, ARG_TYPE> &value) :

また、 which をにキャストvalueARG_TYPEて直接呼び出してoperator ARG_TYPE() から、 にキャストARG_TYPEするTYPE代わりにから に変換し、 からの可能な変換と への呼び出しをTYPEコンパイラに推測させる 必要があります。最初の解決策では、不可能な変換に関するコンパイル エラーがより明確になる場合があります。ARG_TYPEoperator ARG_TYPE()

于 2013-05-03T09:30:40.177 に答える
0

RANGE_TYPE は、TYPE にキャストできる任意の型にすることができます。これを IntegerRange クラスのみに制限したいと思います。IntegerRange のみに制限するには

テンプレート引数の順序を入れ替えて、次のように宣言するだけです。

template<typename TYPE, TYPE2 MIN, TYPE2 MAX>  
struct IntegerRange

これは、テンプレートの引数推定が引数の型を暗黙的に変換しないため、機能します。たとえば、float から int へ。



//range2_t b = a; // This does not work  

もちろん。abさまざまな種類があります。テンプレートの特殊化ごとに、クラスの新しいテンプレートが作成されることに注意してください。タイプが似ているため、2 つのオブジェクトを割り当てることはできません。

class A { int a; }; class B { int a; };
A a; B b; a = b;  // Should not work

そのためには、別a = bの から を構築できるコピー コンストラクタを提供する必要があります。(型変換演算子があるため、ここでは代入は必要ありません。)IntegerRangeIntegerRange

template<typename TYPE2, TYPE MIN2, TYPE MAX2>
IntegerRange(const IntegerRange<TYPE2,MIN2,MAX2>& ot) {
    if (MIN > ot.mValue || ot.mValue > MAX)  
    {  
        throw OutOfRangeError();  
    }  

    mValue = ot.mValue;
}
于 2013-05-03T10:04:41.893 に答える