简体   繁体   English

如何在具有不同模板参数的C ++模板之间隐式转换

[英]How to implicitly cast between C++ templates with different template parameters

I am trying to create a C++ template class wrapping an integer value and checking that this value is always inside a valid range, so the simplified code is the following one: 我试图创建一个包装整数值的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;  
    }  
}  

The previous code works but it has a little drawback when using this class. 以前的代码可以工作,但在使用这个类时它有一些缺点。 Here is a sample: 这是一个示例:

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  

So, to assign values between different ranges I have to explicitly cast to the TYPE given. 因此,要在不同范围之间分配值,我必须明确地转换为给定的TYPE。 I would like to have a solution to avoid having this explicit cast and dealing with IntegerRange class as they were normal integers. 我想有一个解决方案,以避免这种显式转换和处理IntegerRange类,因为它们是正常的整数。 So the developer should have the feeling he is dealing with normal integer instead of classes. 所以开发人员应该感觉他正在处理普通的整数而不是类。

To solve this I tried different things. 为了解决这个问题,我试了不同的东 One working is the following one as an additional constructor: 一个工作是以下一个作为额外的构造函数:

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

However, even if this works, I do not like too much as RANGE_TYPE can be any type able to cast to TYPE, and I would like to restrict this to only IntegerRange classes. 但是,即使这样可行,我也不太喜欢,因为RANGE_TYPE可以是任何能够转换为TYPE的类型,我想将此限制为只有IntegerRange类。 To restrict it only to IntegerRange classes I tried the following but it is not compiling and I do not understand the reason: 要仅将其限制为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();  
    }  
}  

The questions are 2: 问题是2:
* Why the last piece of code is not compiling and what I need to change to compile it. *为什么最后一段代码没有编译,我需要更改以编译它。
* Is there any better to avoid the explicit cast I am missing? *有没有更好的避免我遗漏的明确演员?

Thanks 谢谢

First, you shouldn't use ARG_MAX as a template name since it may already be defined as a POSIX numeric constant. 首先, 您不应该使用ARG_MAX作为模板名称,因为它可能已经被定义为POSIX数字常量。

Secondly, you should remove the typename in the third template argument of IntegerRange : 其次,您应该删除IntegerRange的第三个模板参数中的typename

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

Also maybe you should cast value to ARG_TYPE which will directly call your operator ARG_TYPE() and then let the compiler convert from ARG_TYPE to TYPE instead of casting to TYPE and let the compiler infer the possible conversion from ARG_TYPE and the call to operator ARG_TYPE() . 也许您应该将valueARG_TYPE ,它将直接调用您的operator ARG_TYPE() ,然后让编译器从ARG_TYPE转换为TYPE而不是转换为TYPE并让编译器推断从ARG_TYPE可能的转换和对operator ARG_TYPE()的调用。 With the first solution, the compilation errors regarding impossible conversions may be more explicit. 使用第一种解决方案,有关不可能转换的编译错误可能更明确。

RANGE_TYPE can be any type able to cast to TYPE, and I would like to restrict this to only IntegerRange classes. RANGE_TYPE可以是任何能够转换为TYPE的类型,我想将其限制为只有IntegerRange类。 To restrict it only to IntegerRange 仅限于IntegerRange

Just interchange the order of the template arguments and declare as 只需交换模板参数的顺序并声明为

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

This will work because template argument deduction doesn't implicitly convert arg types. 这将起作用,因为模板参数推导不会隐式转换arg类型。 for example float to int. 例如float到int。



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

Of course. 当然。 a and b have different types. ab有不同的类型。 Remember for each template specialization a new template of the class is created. 请记住,对于每个模板专业化,都会创建该类的新模板。 You can't assign two objects because their types look similar. 您不能分配两个对象,因为它们的类型看起来相似。

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

In order to do a = b you need to provide copy constructor that can construct an IntegerRange from another IntegerRange . 为了做a = b你需要提供可以从另一个IntegerRange构造IntegerRange复制构造函数。 (You don't need assignment here because you have the type conversion operator.) (这里不需要赋值,因为你有类型转换运算符。)

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;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM