std::midpoint不能盲目替换(a+b)/2,需满足C++20、类型严格匹配、语义合理等条件;它对整数返回向下取整中点,结果类型与参数一致,不自动防溢出或提升精度。

直接用 std::midpoint 替换 (a + b) / 2 并不能自动防溢出——它只在类型匹配、语义合理、编译器启用 C++20 的前提下才真正起作用。盲目替换反而可能引入编译错误或逻辑偏差。
std::midpoint 编译失败的常见原因
它对类型极其严格,不是“能算就调用”,而是“类型不对就拒斥”:
-
std::midpoint(10, 20U)失败:int和unsigned int类型不一致,不触发隐式转换,直接 SFINAE 掉或编译报错 -
std::midpoint(1.5f, 2.5f)在部分标准库实现中虽可编译(C++20 允许浮点重载),但行为等价于(a + b) / 2,无安全增益,还可能因量级差异放大误差 -
std::midpoint(v.begin(), v.end())失败:迭代器不是原生指针,除非满足LegacyRandomAccessIterator且重载了-和+,否则不参与模板推导 - 没加
-std=c++20:GCC/Clang 默认不启用 C++20,std::midpoint不可见;MSVC 2019 需显式设为 C++20 工具集
整数中点计算时的符号与舍入规则
它不返回数学平均值,而是向下取整的中点(floor((a + b) / 2.0)),这对二分查找索引至关重要:
-
std::midpoint(-3, 2)返回-1,不是0或-0.5向零取整结果 -
std::midpoint(5, 1)返回3,即floor(6 / 2) == 3,即使a > b也定义良好,但业务上需自行判断是否合法 - 结果类型与参数完全一致:
std::midpoint(short{1}, short{3})返回short,不会提升为int,避免意外截断 - 对
size_t等无符号类型,b 时 <code>b - a回绕,结果仍数学正确(模意义下中点),但通常不符合业务预期——此时应先校验区间有效性
指针中点计算:唯一不可替代的场景
这是 std::midpoint 唯一提供**编译期+运行期双重保障**的用途,手动写 begin + (end - begin) / 2 可能触发未定义行为:
立即学习“C++免费学习笔记(深入)”;
-
std::midpoint(begin, end)要求begin和end指向同一数组(含 one-past-the-end),否则未定义;而手写减法若end - begin超出ptrdiff_t表示范围,直接 UB - 它不接受
void*、const T*与T*混用——类型必须精确匹配,强制你在编译期暴露 const 正确性问题 - 示例:
int* p = new int[SIZE_MAX / sizeof(int) + 1]; auto mid = std::midpoint(p, p + N);安全,哪怕N接近SIZE_MAX / sizeof(int) - 注意:它不检查
p是否有效、N是否越界——内存安全仍由你负责,它只保“算得对”
真正容易被忽略的是:它从不介入业务逻辑约束。传进去两个合法 int,它就返回合法中点;传进去两个悬空指针,它也可能“成功”返回一个地址——安全边界仅限数值/指针算术本身,不在语义层兜底。


















