POD 类型如何添加对 reinterpret_cast 的支持?
How can a POD type add support for reinterpret_cast'ing it?
我正在尝试替换一个类型,typedef
从内置整数类型中提取,用于大型项目中的自定义 class,它将实现一些额外的功能,例如避免赋值截断等。但该项目广泛使用像 reinterpret_cast<void*>(value)
这样的转换。我天真地尝试在我的新 class 中实现 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
}
我认为如果 class 是 POD,这将允许我做类似 reinterpret_cast
的事情。但是这段代码给我一个编译错误:
invalid cast from type ‘Value’ to type ‘void*’
那么我的问题是:如何添加对 reinterpret_cast
的支持,这样我就不必在项目的每个部分手动将其切换为 static_cast
?
不幸的是,reinterpret_cast
不是为此而设计的。这适用于 POD 类型的原因是 cppreference website:
上的#3
A value of any integral or enumeration type can be converted to a pointer type. A pointer converted to an integer of sufficient size and back to the same pointer type is guaranteed to have its original value, otherwise the resulting pointer cannot be dereferenced safely (the round-trip conversion in the opposite direction is not guaranteed; the same pointer may have multiple integer representations) The null pointer constant NULL or integer zero is not guaranteed to yield the null pointer value of the target type; static_cast or implicit conversion should be used for this purpose.
而且,我相信 §12.3.2 在这里发挥了作用:
A conversion function is never used to convert a (possibly cv-qualified) object to the (possibly cv-qualified) same object type (or a reference to it), to a (possibly cv-qualified) base class of that type (or a reference to it), or to (possibly 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. 理想情况下,但可能不现实,修复需要将 classes 转换为 void
的底层设计问题
没有。 3 可能是这里最不痛苦的解决方案。
编辑评论
这里有两种方式:
1. 使用重载的寻址运算符 (operator&
)。这可能无法实现,具体取决于 Value
的使用方式。
#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
}
2.实现一个运算符uintptr_t
。虽然这需要冗长的双重转换,但它会将转换转移到 Value
class,而 uintptr_t
是 guaranteed 以便能够容纳 void*
。
#include <cstdlib>
struct Value
{
size_t value;
operator uintptr_t() { return static_cast<uintptr_t>(value); }
};
int main()
{
Value v;
void* p=reinterpret_cast<void*>(static_cast<uintptr_t>(v)); // This is how the project uses it
// or less verbose
void* p2=reinterpret_cast<void*>(uintptr_t(v));
}
C++ 语言不允许覆盖 reinterpret_cast
。参见 Overloading c++ typecasting (functions)
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 专门化模板。
您可以将调用站点更改为适用于两种转换的形式:
void* p = reinterpret_cast<void*&>(v);
add this character ^
这有效地将 'v' 视为一个包含 void* 的对象,这在这两种情况下都是正确的。自动左值到右值转换将插入取消引用,提取原始 size_t 或嵌入的 size_t 到 Value.
此代码等同于:
void* p = *reinterpret_cast<void**>(&v);
然而,没有办法让 reinterpret_cast 在您的对象上调用自定义运算符; reinterpret_cast的重点是它完全不可见。
我正在尝试替换一个类型,typedef
从内置整数类型中提取,用于大型项目中的自定义 class,它将实现一些额外的功能,例如避免赋值截断等。但该项目广泛使用像 reinterpret_cast<void*>(value)
这样的转换。我天真地尝试在我的新 class 中实现 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
}
我认为如果 class 是 POD,这将允许我做类似 reinterpret_cast
的事情。但是这段代码给我一个编译错误:
invalid cast from type ‘Value’ to type ‘void*’
那么我的问题是:如何添加对 reinterpret_cast
的支持,这样我就不必在项目的每个部分手动将其切换为 static_cast
?
不幸的是,reinterpret_cast
不是为此而设计的。这适用于 POD 类型的原因是 cppreference website:
A value of any integral or enumeration type can be converted to a pointer type. A pointer converted to an integer of sufficient size and back to the same pointer type is guaranteed to have its original value, otherwise the resulting pointer cannot be dereferenced safely (the round-trip conversion in the opposite direction is not guaranteed; the same pointer may have multiple integer representations) The null pointer constant NULL or integer zero is not guaranteed to yield the null pointer value of the target type; static_cast or implicit conversion should be used for this purpose.
而且,我相信 §12.3.2 在这里发挥了作用:
A conversion function is never used to convert a (possibly cv-qualified) object to the (possibly cv-qualified) same object type (or a reference to it), to a (possibly cv-qualified) base class of that type (or a reference to it), or to (possibly 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. 理想情况下,但可能不现实,修复需要将 classes 转换为 void
的底层设计问题没有。 3 可能是这里最不痛苦的解决方案。
编辑评论
这里有两种方式:
1. 使用重载的寻址运算符 (operator&
)。这可能无法实现,具体取决于 Value
的使用方式。
#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
}
2.实现一个运算符uintptr_t
。虽然这需要冗长的双重转换,但它会将转换转移到 Value
class,而 uintptr_t
是 guaranteed 以便能够容纳 void*
。
#include <cstdlib>
struct Value
{
size_t value;
operator uintptr_t() { return static_cast<uintptr_t>(value); }
};
int main()
{
Value v;
void* p=reinterpret_cast<void*>(static_cast<uintptr_t>(v)); // This is how the project uses it
// or less verbose
void* p2=reinterpret_cast<void*>(uintptr_t(v));
}
C++ 语言不允许覆盖 reinterpret_cast
。参见 Overloading c++ typecasting (functions)
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 专门化模板。
您可以将调用站点更改为适用于两种转换的形式:
void* p = reinterpret_cast<void*&>(v);
add this character ^
这有效地将 'v' 视为一个包含 void* 的对象,这在这两种情况下都是正确的。自动左值到右值转换将插入取消引用,提取原始 size_t 或嵌入的 size_t 到 Value.
此代码等同于:
void* p = *reinterpret_cast<void**>(&v);
然而,没有办法让 reinterpret_cast 在您的对象上调用自定义运算符; reinterpret_cast的重点是它完全不可见。