因为static_cast不进行编译期逻辑合理性检查,而TypeSafeCast通过std::is_constructible_v等trait在编译期拒绝非法转换,仅允许有语义支撑的构造或赋值操作。

为什么不能直接用 static_cast 做类型安全检查
因为 static_cast 在编译期不校验转换逻辑是否合理——比如把 int* 强转成 double*,它不会报错,但运行时大概率崩。真正需要的是“在编译期就拒绝明显非法的转换”,比如 std::string → int 这种无定义转换。
标准库里 std::is_convertible_v<From, To> 只能判断隐式转换是否存在,而很多我们想拦住的转换(如指针跨类型 reinterpret)其实是“可编译但不该发生”的场景。
- 目标不是替代
static_cast,而是给它加一道编译期闸门 - 要支持自定义类型、内置类型、指针、引用,但不希望泛化到所有组合
- 关键点:拒绝
reinterpret_cast等价行为,只允许明确有语义支撑的转换
用 std::is_constructible_v 和 std::is_assignable_v 组合判断
这两个 trait 比 is_convertible_v 更贴近实际使用意图:构造和赋值才是用户真正要做的操作。它们天然排除了裸指针 reinterpret、void* 转换等危险路径。
例如:std::is_constructible_v<int, std::string> 是 false,而 std::is_constructible_v<std::string, const char*> 是 true —— 这正是我们想要的粒度。
立即学习“C++免费学习笔记(深入)”;
- 对值类型,优先用
std::is_constructible_v<To, From&&>(考虑右值引用) - 对引用类型,额外检查
std::is_assignable_v<To&, From&&>,避免绑定临时对象失败 - 对指针类型,禁用裸指针之间的相互转换(除非是
void*或相同 cv-qualified 类型)
模板类 TypeSafeCast 的核心实现
它不执行转换,只做编译期断言;转换仍由 static_cast 完成,但前提是通过检查:
template <typename To, typename From>
struct TypeSafeCast {
static_assert(
std::is_constructible_v<To, From&&> ||
(std::is_reference_v<To> && std::is_assignable_v<To, From&&>) ||
(std::is_pointer_v<To> && std::is_pointer_v<From> &&
(std::is_same_v<std::remove_cvref_t<To>, std::remove_cvref_t<From>> ||
std::is_same_v<std::remove_cvref_t<To>, void*> ||
std::is_same_v<std::remove_cvref_t<From>, void*>)),
"Unsafe or undefined conversion detected"
);
};注意三点:
-
std::remove_cvref_t必须用,否则const int*&和int*会被判为不同 - 允许
void*作为中转指针,但禁止int*↔double*这类 reinterpret 场景 - 没覆盖
enum→int这类隐式整型提升,那是语言规则,不属于“类型转换检查”范畴
怎么在实际代码里用这个检查类
别把它当运行时工具,它的价值全在编译期。典型用法是配合 constexpr if 或 SFINAE 做分支,或者直接用于模板约束:
template <typename T, typename U>
auto safe_convert(U&& u) {
TypeSafeCast<T, std::decay_t<U>>{}; // 编译期触发 static_assert
return static_cast<T>(std::forward<U>(u));
}调用 safe_convert<int>("123") 会立刻报错,而 safe_convert<std::string>("hello") 顺利通过。
- 不要在函数体里写
if constexpr去绕过检查——那等于自己拆掉闸门 - 如果项目用 C++20,可用
requires替代static_assert,错误信息更清晰 - 对 move-only 类型(如
std::unique_ptr),确保传入的是右值引用,否则is_constructible_v会失败
最易忽略的点:模板参数推导时 From 的 cv-qualifiers 和引用性必须显式保留,否则 std::decay_t 会抹掉关键信息,导致检查失效。


















