std::is_swappable_v 仅检测 ADL 下 swap(a,b) 表达式是否合法,不保证语义正确或无异常;例如 std::vector 因 swap 是成员函数而非自由函数而返回 false,需显式提供命名空间内非模板 swap 函数或改用 std::is_swappable_with_v。

std::is_swappable 是什么,它真能判断“能不能 swap”?
不能。它只检查 swap(a, b) 在 ADL(参数依赖查找)下是否合法,不保证语义正确或无异常。比如自定义类型重载了 swap 但内部抛异常,std::is_swappable_v 仍为 true。
它本质是探测表达式可求值性,不是运行时行为验证。常见误用是把它当“安全交换前提”,实际还需配合 noexcept 检查(如 std::is_nothrow_swappable_v)。
为什么 std::is_swappable_v<:vector>> 返回 false?
因为标准库中 std::vector 的 swap 是成员函数 v1.swap(v2),而非自由函数;而 std::is_swappable 依赖 ADL 查找自由函数 swap(x, y) —— 它不会退化到找成员函数。
解决方法有二:
- 显式提供自由函数
swap(通常在类同名命名空间内) - 改用
std::is_swappable_with_v,它更宽松,会尝试多种调用形式(包括成员调用)
例如:std::is_swappable_with_v<:vector>, std::vector 就是 true。
自定义类型怎么让 is_swappable_v 生效?
必须在类所在命名空间中定义非成员 swap 函数,并支持 ADL。不能放在全局或别的命名空间里,否则查不到。
典型写法:
namespace my_ns {
struct X { int v; };
void swap(X& a, X& b) noexcept { std::swap(a.v, b.v); }
}
static_assert(std::is_swappable_v<:x>); // ✅
</:x>
注意点:
- 函数必须是非模板的(特化可以,但主模板不行),否则 ADL 失效
- 推荐加
noexcept,否则std::is_nothrow_swappable_v仍为false - 不要在类内部声明
friend void swap(...)而不定义——声明不触发 ADL,定义必须在命名空间作用域
和 std::is_move_constructible 等其他特性检查混用时要注意什么?
std::is_swappable 不隐含任何构造、赋值或移动能力。一个类型可能可交换但不可移动(比如禁用了移动构造),也可能可移动但不可交换(比如没提供 swap)。
典型陷阱:
- 容器算法(如
std::sort)内部可能用swap,但只依赖std::is_swappable_with,不检查移动性 - 若你写泛型代码并想 fallback 到移动+复制模拟 swap,需同时检查
std::is_move_constructible_v和std::is_move_assignable_v -
std::is_swappable_v对内置类型(如int)返回true,是因为标准提供了std::swap,且 ADL 找得到
真正稳妥的交换判定往往需要组合多个 trait,而不是单靠一个 is_swappable。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











