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 类,因为它们是普通整数。所以开发者应该感觉到他在处理普通的整数而不是类。

为了解决这个问题,我尝试了不同的东西。一种工作是以下作为附加构造函数:

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

首先,您不应该将ARG_MAX其用作模板名称,因为它可能已经被定义为POSIX数字常量。

其次,您应该删除typename第三个模板参数中的IntegerRange

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

另外,也许您应该value转换为ARG_TYPEwhich 将直接调用您operator ARG_TYPE() ,然后让编译器从转换ARG_TYPETYPE而不是转换为TYPE并让编译器推断可能的转换 from ARG_TYPE和对operator ARG_TYPE(). 使用第一个解决方案,关于不可能转换的编译错误可能更加明确。

于 2013-05-03T09:30:40.177 回答
0

RANGE_TYPE 可以是任何能够转换为 TYPE 的类型,我想将其限制为仅 IntegerRange 类。仅将其限制为 IntegerRange

只需交换模板参数的顺序并声明为

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

这将起作用,因为模板参数推导不会隐式转换 arg 类型。例如浮动到 int。



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

当然。a并且b有不同的类型。请记住,对于每个模板特化,都会创建一个新的类模板。您不能分配两个对象,因为它们的类型看起来相似。

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

为了做到这一点,a = b您需要提供可以IntegerRange从另一个构造一个的复制构造函数IntegerRange。(这里不需要赋值,因为你有类型转换运算符。)

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 回答