如何为内置的用户定义类型获得相同的强制转换,例如:
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
答案 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)
我认为没有办法为你的演员创建自己的编译器警告。