C ++:为用户定义的类型进行转换

时间:2009-10-06 21:51:14

标签: c++ visual-studio-2008 casting compiler-errors compiler-warnings

如何为内置的用户定义类型获得相同的强制转换,例如:

float a = 5.4;
std::string s = a;//error, no conversion avaible
int x = a;//warning, possible data loss
int y = (int)a;//fine
int z = static_cast<int>a;//fine
float b = c;//warning, possible data loss

现在说我有自己的Int和Float类,如何获得相同的错误和警告?

class Int
{
public:
    int value;
    Int(int v);
    ...
};
class Float
{
public:
    float value;
    Float(float v);
    ...
};
Int c = 10;
Float a = 5.5;
std::string s = a;
Int x = a;
Int y = (Int)a;
Int z = static_cast<Int>a;
Float b = c;

我知道创建重载的转换操作符和使用构造函数,但是我不知道如何使这个工作正确地用于隐式和显式转换,例如考虑。如果我不在这些方法中添加显式强制转换,那么我会在编译时收到警告,但是当他们调用时没有,如果我这样做,那么我在类代码中没有得到错误,但我仍然没有得到当使用其中任何一个时发出警告。

我猜测有一些方法可以将强制转换操作符标记为显式,因此如果它尝试隐式转换而不是使用显式(C-Style或static_cast)强制转换,则会生成警告

编辑: 好吧,我想我可以在这样的情况下得到它,其中所有类型都是完全的,已知的,但是当一个或两个都是模板时,并且两种类型都没有映射到内置类型的情况呢?

template<typename T> class Vector2
{
public:
    T x, y;
    Vector2():x(0),y(0){}
    Vector2(T x, T y):x(x),y(y){}

    //Works as expected, warning if adding T and T2 is unsafe, or error if
    //incompatible*/
    template<typename T2>Vector2<T>& operator += (const Vector2<T2> &v);
    //Also works as desired
    Vector2<T>& operator *= (T s);

    //allows the conversion, but always generates warnings if 
    //T and T2 would, even if this constructor is used by an explicit
    //case. How can I suppress the warnings for the explicit cast, but
    //not for implicit casts?
    template<typename T2>Vector2(const Vector2<T2> &v);//uses implicit conversion form T2 to T
};

从Vector2到Vector2的隐式强制转换按预期工作,但是从Vector2到Vector2的强制转换总是会导致(2,一个用于x,一个用于y)警告,即使使用了显式的C-Style或static_cast也是如此。我想保留隐式演员的警告,但不是明确的演员。

我知道我可以解决这个问题,即创建一个特殊的T vector_cast(T2)类型方法,该方法在内部对每个元素使用显式强制转换,但Id更能够使用C-Style和static_casts

3 个答案:

答案 0 :(得分:1)

你想要的一些东西是不可能的,因为它依赖于编译器对所涉及类型的特殊知识,你不能教这些东西。

您展示的项目应执行以下操作:

Float a = 5.5;

应该无怨无悔地工作。

std::string s = a;

应该给出一些编译器错误,不一定与使用POD浮点数相同,但它仍然会拒绝,因为你的Float没有const char *运算符。 (如果确实如此,请删除它以导致此错误。)

Int x = a;

除非Float有“operator int()”,否则你仍然应该收到有关可能的数据丢失的警告。如果是这样,删除它,因此编译器被强制使用“operator float()”,从而导致警告。

Int y = (int)a;

应该无怨无悔地工作。

Int z = static_cast<int>a;

这应该具有与前一个相同的明显效果。 (它们之间存在技术差异,但在这种情况下,它们无关紧要。)

Float b = c;

你没有显示'c'是什么,所以我不知道这会做什么。

答案 1 :(得分:1)

我认为也没有办法。我能做到的最好的就是你要生成警告的行根本不能编译。

class Int
{
public:
    int value;
    Int(int v);
};

class Float
{
public:
    float value;
    Float(float v);
    operator int() { return static_cast<int>(value); }
};

int main()
{
    Float a = 5.5;
    //Int x = a; //no warning, simply doesn't compile
    Int y = (int)a;
    Int z = static_cast<int>(a);
}

编辑:关于您关于Vector2的问题

要做的一件事可能是禁用不同Vector2类型之间的所有隐式转换。作为捷径,您可以提供vector_cast以允许显式转化:

template <class T, class S>
Vector2<T> vector_cast(const Vector2<S>& s)
{
    return Vector2<T>(static_cast<T>(s.x), static_cast<T>(s.y));
}

另一件事可能是引入一些模板元编程,以启用转换构造函数以进行安全转换。

在我看来,提升不包含这样的type_trait,因此我自己动手了。

有些简化:Target必须至少与Source一样大,如果Source是浮点,则Target不能是整数。但是,它忽略了签名问题,以及浮点类型是否可以表示整数类型的整个范围的问题(例如,float不能精确地存储所有32位整数,但可以双重存储)。

#include <boost/type_traits.hpp>
#include <boost/utility/enable_if.hpp>

template <class S, class T>
struct is_safe_conversion:
    boost::integral_constant<
        bool,
        (sizeof(S) <= sizeof(T)) && !(boost::is_floating_point<S>::value && boost::is_integral<T>::value)
    >
{
};

template<typename T> class Vector2
{
public:
    T x, y;
    Vector2():x(0),y(0){}
    Vector2(T x, T y):x(x),y(y){}

    template <class U>
    Vector2(const Vector2<U>& other, typename boost::enable_if<is_safe_conversion<U, T> >::type* = 0):
        x(other.x), y(other.y) {}

};

template <class T, class S>
Vector2<T> vector_cast(const Vector2<S>& s)
{
    return Vector2<T>(static_cast<T>(s.x), static_cast<T>(s.y));
}

int main()
{
    Vector2<double> vd, vd2;
    Vector2<int> vi, vi2;
    Vector2<float> vf, vf2;

    vd = vd2;
    vd = vi;
    vd = vf;

    //vi = vd; //error
    vi = vector_cast<int>(vd);
    vi = vi2;
    //vi = vf; //error
    vi = vector_cast<int>(vf); //explicit

    //vf = vd; //error
    vf = vector_cast<float>(vd);

    //following compiles, but produces a warning (float cannot represent all integers) 
    //TODO: enhance is_safe_conversion!
    vf = vi; 
    vf = vf2;
}

答案 2 :(得分:0)

我认为没有办法为你的演员创建​​自己的编译器警告。