如何在转换类型时保留值类别与cv限定符?
实现保留值类别与cv限定符的类型转换函数
perfect_cast 问题背景
C++中的std::forward仅能转发原有类型的值类别和cv限定符,无法完成跨类型转换。我们需要一个perfect_cast函数,在将输入转换为目标类型的同时,完整保留原参数的左值/右值属性以及const、volatile限定符,确保重载函数能正确匹配调用。
实现方案
C++23 简洁实现
C++23引入的std::forward_like原生支持这类需求——它会参照指定模板参数的引用类型和cv限定,转发目标对象,完美保留原有的值类别和属性:
#include <iostream> #include <type_traits> #include <format> #include <utility> template <typename To, typename From> decltype(auto) perfect_cast(From&& s) { return std::forward_like<From>(static_cast<To&&>(s)); } // 以下为测试代码 template <std::size_t I> struct A { void f()& { std::cout << std::format("lvalue A{:d}", I) << std::endl; } void f() const& { std::cout << std::format("const lvalue A{:d}", I) << std::endl; } void f()&& { std::cout << std::format("rvalue A{:d}", I) << std::endl; } void f() const&& { std::cout << std::format("const rvalue A{:d}", I) << std::endl; } }; template <std::size_t ...Is> struct B : A<Is>... { }; auto g1() { return B<0, 1, 2, 3>{}; } const auto g2() { return B<0, 1, 2, 3>{}; } int main() { B<0, 1, 2, 3> b; auto& b1 = b; perfect_cast<A<0>>(b1).f(); const auto& b2 = b1; perfect_cast<A<1>>(b2).f(); perfect_cast<A<2>>(g1()).f(); perfect_cast<A<3>>(g2()).f(); }
C++20及更早版本手动实现
如果使用C++20或更早版本,需要手动推导原参数的属性并构造对应目标类型:
#include <iostream> #include <type_traits> #include <format> template <typename To, typename From> decltype(auto) perfect_cast(From&& s) { using FromNoRef = std::remove_reference_t<From>; // 为目标类型添加原参数的const限定 using QualifiedTo = std::conditional_t<std::is_const_v<FromNoRef>, std::add_const_t<To>, To>; if constexpr (std::is_lvalue_reference_v<From>) { // 原参数是左值,返回带cv限定的左值引用 return static_cast<QualifiedTo&>(s); } else { // 原参数是右值,返回带cv限定的右值引用 return static_cast<QualifiedTo&&>(s); } } // 测试代码与上述C++23版本一致
原理说明
- C++23版本:
std::forward_like<From>会自动匹配From的引用类型(左值/右值)和cv限定,结合static_cast<To&&>完成类型转换,直接实现需求。 - 手动实现版本:
- 提取原参数的基础类型(移除引用),判断其是否带有
const限定并传递给目标类型。 - 根据原参数的引用类型,返回对应类别的目标类型引用,确保值类别和cv限定被完整保留,触发正确的重载函数。
- 提取原参数的基础类型(移除引用),判断其是否带有
测试结果
编译运行代码后,输出符合预期:
lvalue A0 const lvalue A1 rvalue A2 const rvalue A3
内容的提问来源于stack exchange,提问作者El Mismo Sol
相关产品推荐
相关产品推荐

