1

如何获得与内置的用户定义类型相同的转换处理,例如:

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

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

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

4

3 回答 3

1

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

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

Float a = 5.5;

应该毫无怨言地工作。

std::string s = a;

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

Int x = a;

您仍然应该在此处收到有关可能丢失数据的警告,除非 Float 具有“运算符 int()”。如果是这样,请将其删除,因此编译器被迫使用“operator float()”,从而导致警告。

Int y = (int)a;

应该毫无怨言地工作。

Int z = static_cast<int>a;

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

Float b = c;

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

于 2009-10-06T22:03:31.633 回答
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));
}

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

在我看来 boost 不包含这样的 a type_trait,因此我推出了自己的。

稍微简化了一点:Target 必须至少和 Source 一样大,如果 Source 是浮点数,Target 不能是整数。但是,它忽略了符号问题,以及浮点类型是否可以表示整数类型的全部范围的问题(例如,float 不能精确存储所有 32 位整数,但 double 可以)。

#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;
}
于 2009-10-06T22:06:54.363 回答
0

我认为没有任何方法可以为您的演员创建​​自己的编译器警告。

于 2009-10-06T21:55:27.810 回答