You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C++中ADL调用std::ranges::size为何要求非const size函数?

std::ranges::size 两个删除重载的设计逻辑

这两个预置的删除size函数是C++20 ranges定制点对象(CPO)的标准拦截设计,核心目的是统一size操作的语义约束,避免ADL(参数依赖查找)意外匹配到语义不符合要求的重载,设计逻辑可拆分为两点说明:

1. 删除重载的核心作用

在通过ADL查找自定义非成员size时加入这两个删除候选,本质是做两层防护:

  • 拦截泛型歧义:避免ADL意外匹配到关联命名空间中定义的过于泛化的size模板(比如第三方库定义的template<class T> auto size(T&&)),这类泛型重载可以匹配任意类型,会完全破坏std::ranges::size的定制语义。加入这两个删除的模板重载后,无意义的泛型size匹配优先级不会高于标准预置的删除版本,会直接触发编译错误,避免语义被篡改。
  • 强制语义合规:size操作本身的语义约定是不修改范围对象、常数时间返回元素个数,这和标准库容器size() const成员函数的语义完全对齐。如果自定义的非成员size只能绑定非const左值引用,本质上暗示该操作可能修改范围,不符合ranges对size的语义要求,删除重载会在重载决议阶段拦截这类不符合约定的实现。

你遇到的加const就报错的问题,本质是重载决议的匹配规则导致的:当你定义size_t size(const Test&)时,该函数和标准预置的void size(const auto&) = delete模板对const引用参数的匹配优先级相同,若没有其他更优匹配路径,就会因为选中删除函数触发编译错误。

2. 为什么该约束仅对非成员size生效

这个约束只作用于非成员size的查找路径,核心原因是两类查找的逻辑完全不同:

  • 成员size的查找是直接检查t.size()表达式的合法性,查找范围仅包含当前类型及其基类的成员函数,不会向外查找其他命名空间的无关函数,不存在ADL带来的泛型匹配歧义,自然不需要额外插入删除重载做拦截。同时成员查找天然遵循const限定符规则,只有const成员函数才能被const对象、右值对象调用,和ranges的语义要求天然对齐。
  • 非成员size依赖ADL查找,查找范围会覆盖参数类型的所有关联命名空间,很容易匹配到无关的泛型size实现,必须靠删除重载做拦截,才能保证语义一致性。

内容的提问来源于stack exchange,提问作者zjyhjqs

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.02 04:54:25