C++类型转换时保留const、指针等原类型属性的实现方法
问题说明
我需要找到一种在类型转换时保留原类型的指针、const限定等属性的方法,示例如下:
template<typename type> void test(type t) { std::cout << "t const? = " << std::is_const<decltype(t)>() << std::endl; int x = (int) t; std::cout << "x const? = " << std::is_const<decltype(x)>() << std::endl; }; int main() { const int x = 0; int y = 0; test<const int>(x); test<int>(y); }
当前代码运行输出:
>>> t const? = 1 >>> x const? = 0 >>> t const? = 0 >>> x const? = 0
预期输出为当模板参数为const类型时,转换得到的x也为const类型:
>>> t const? = 1 >>> x const? = 1 >>> t const? = 0 >>> x const? = 0
约束条件
- 不使用
if constexpr分支判断的写法,反例如下:
// bad if constexpr (std::is_const<decltype(t)>()) { // do const cast } else { // do non const cast }
- 实际应用场景:持有const或非const的void指针,需要将其转换为指定类型的指针,同时保留原指针的const属性
- 直接使用
type x = (type) t的方案不适用实际场景,需要基于类型特征(type traits)的解决方案
解决方案
通过编译期类型萃取实现cv限定符的拷贝,全程无运行时分支,纯类型计算,兼容C11及以上标准,C20可直接使用标准库提供的现成工具。
基础实现
首先实现通用的cv属性拷贝萃取,将源类型的const/volatile限定符拷贝到目标类型上:
#include <type_traits> // 萃取定义:默认无cv属性 template <typename Src, typename Dst> struct copy_cv { using type = Dst; }; // 偏特化:源类型带const template <typename Src, typename Dst> struct copy_cv<const Src, Dst> { using type = const Dst; }; // 偏特化:源类型带volatile template <typename Src, typename Dst> struct copy_cv<volatile Src, Dst> { using type = volatile Dst; }; // 偏特化:源类型带const+volatile template <typename Src, typename Dst> struct copy_cv<const volatile Src, Dst> { using type = const volatile Dst; }; // 别名模板简化调用 template <typename Src, typename Dst> using copy_cv_t = typename copy_cv<Src, Dst>::type;
修改原示例代码中的x定义,用萃取得到的类型声明变量即可得到预期结果:
template<typename type> void test(type t) { std::cout << "t const? = " << std::is_const<decltype(t)>() << std::endl; // 将入参t的cv属性拷贝到int类型上,自动适配const/非const场景 copy_cv_t<type, int> x = static_cast<int>(t); std::cout << "x const? = " << std::is_const<decltype(x)>() << std::endl; };
适配void指针转换场景
针对void指针转指定类型指针的需求,在上述cv拷贝萃取的基础上扩展指针层级处理即可:
// 指针转换萃取:输入源指针类型、目标指向类型,输出带源指针cv属性的目标指针类型 template <typename SrcPtr, typename Dst> struct cast_ptr_cv; // 偏特化匹配裸指针类型 template <typename SrcPointee, typename Dst> struct cast_ptr_cv<SrcPointee*, Dst> { using type = copy_cv_t<SrcPointee, Dst>*; }; // 别名模板简化调用 template <typename SrcPtr, typename Dst> using cast_ptr_cv_t = typename cast_ptr_cv<SrcPtr, Dst>::type;
使用示例:
void usage_example() { int normal_val = 1; const int const_val = 2; void* normal_void_ptr = &normal_val; const void* const_void_ptr = &const_val; // 普通void*转int*,无const限定 cast_ptr_cv_t<decltype(normal_void_ptr), int> int_ptr = static_cast<cast_ptr_cv_t<decltype(normal_void_ptr), int>>(normal_void_ptr); // const void*转const int*,自动携带const限定 cast_ptr_cv_t<decltype(const_void_ptr), int> const_int_ptr = static_cast<cast_ptr_cv_t<decltype(const_void_ptr), int>>(const_void_ptr); // 编译期校验类型正确性 static_assert(std::is_same_v<decltype(int_ptr), int*>); static_assert(std::is_same_v<decltype(const_int_ptr), const int*>); }
如果使用C++20及以上标准,可以直接用标准库的std::copy_cv_t替代自定义的copy_cv_t,无需手动实现cv拷贝萃取。
内容的提问来源于stack exchange,提问作者Jaan
相关产品推荐
相关产品推荐

