我正在尝试从具有自定义类的大型项目中使用的内置整数类型替换类型typedef
',这将实现一些额外的功能,例如避免在分配时截断等。但该项目广泛使用reinterpret_cast<void*>(value)
之类的转换。我在新课程中实现了operator void*()
的天真尝试,但显然这不能使reinterpret_cast
成为可能,只允许static_cast
到void*
。这是代码:
#include <cstdlib>
#include <type_traits>
#define USE_NEW_VALUE_TYPE
#ifdef USE_NEW_VALUE_TYPE
struct Value
{
size_t value;
operator void* () { return reinterpret_cast<void*>(value); }
};
static_assert(std::is_pod<Value>::value,"Value is not POD");
#else
typedef size_t Value;
#endif
int main()
{
Value v{5};
void* p=reinterpret_cast<void*>(v); // This is how the project uses it
}
我认为如果课程是POD,这将允许我做reinterpret_cast
这样的事情。但是这段代码给了我一个编译错误:
从“值”类型无效转换为“void *”
类型
那么我的问题就是:如何添加对这样的reinterpret_cast
的支持,这样我就不必在项目的每个部分手动将其切换到static_cast
?
答案 0 :(得分:3)
不幸的是,reinterpret_cast
不适用于此。这适用于POD类型的原因是cppreference website上的#3:
任何整数或枚举类型的值都可以转换为指针类型。转换为足够大小的整数并返回相同指针类型的指针保证具有其原始值,否则无法安全地解除引用结果指针(不保证相反方向的往返转换;同一指针可能有多个整数表示)空指针常量NULL或整数零不保证产生目标类型的空指针值; static_cast或隐式转换应该用于此目的。
而且,我相信§12.3.2在这里起作用:
转换函数永远不会用于将(可能是cv限定的)对象转换为(可能是cv限定的)相同的对象类型(或对它的引用),转换为(可能是cv限定的)基类类型(或对它的引用),或(可能是cv-qualified) void 。
简而言之:用户定义的转化不参与reinterpret_casts
的解析。
可能的解决方案
1。明确地使用v:
的地址 void* p=reinterpret_cast<void*>(&v);
2。像你一样定义operator void*()
,你可以写
void *p = v;
注意:由于不必要的隐式转换,这可能会导致问题虫洞
3。按照您自己的说法使用static_cast
。
注意:使用&v
而不是定义operator void*()
的原因与第2号相同
4。理想情况下,但可能不切实际,修复需要将类转换为无效的基础设计问题
没有。 3可能是最难以解决的解决方案。
编辑评论
这里有两种方式:
1。使用重载的地址操作符(operator&
)。根据{{1}}的使用方式,这可能无法实现。
Value
2。实施运营商#include <cstdlib>
struct Value
{
size_t value;
void* operator &() { return reinterpret_cast<void*>(value); }
};
int main()
{
Value v;
void* p=reinterpret_cast<void*>(&v); // This is how the project uses it
}
。虽然这需要详细的双重转换,但它会将转换转移到uintptr_t
类,Value
为guaranteed,以便能够保留uintptr_t
。
void*
答案 1 :(得分:0)
C ++语言不允许覆盖reinterpret_cast
。见Overloading c++ typecasting (functions)
答案 2 :(得分:0)
1)用辅助函数替换所有这些强制转换,如:
template <class T>
void* integer_to_voidptr(T t)
{
return reinterpret_cast<void*>(t);
}
template <class T>
T voidptr_to_integer(void* p)
{
return reinterpret_cast<T>(p);
}
2)添加非模板重载或专门为您的POD模板。
答案 3 :(得分:0)
您可以将呼叫网站更改为适用于两种演员表的表单:
void* p = reinterpret_cast<void*&>(v);
add this character ^
这有效地对待&#39; v&#39;作为保持空*的对象,在两种情况下都是如此。自动左值到右值转换将插入一个去引用,在Value中提取原始size_t或嵌入的size_t。
此代码相当于:
void* p = *reinterpret_cast<void**>(&v);
但是没有办法让reinterpret_cast调用你对象的自定义操作符; reinterpret_cast的重点是它完全不可见。