std::common_reference用于为满足common_reference_with概念的类型对推导共同引用类型,典型应用于迭代器适配器中统一value_type的引用行为,如将const t&和t&&映射到const t&。

std::common_reference 是干啥的?
它不是用来“推导引用类型”的万能工具,而是为满足 std::common_reference_with 概念的一对类型找一个共同的、可绑定的引用类型——典型场景是迭代器适配器里要统一 value_type 的引用行为,比如把 const T& 和 T&& 映射到 const T&。
常见错误现象:std::common_reference<t const u>::type</t> 编译失败,不是因为写错了,而是这两者根本没定义公共引用(比如 T 和 U 不相关,或 cv 限定不兼容)。
使用场景集中在:
- 自定义迭代器的
reference类型推导(尤其配合std::ranges::iterator_t) - 实现类似
zip_view这种多迭代器组合时,统一解引用结果的引用类别 - 写泛型算法时想安全地声明“我能接受任意可共引用的 pair”
注意:它依赖 ADL 可见的 common_reference 特化,标准库只对基础引用组合(如 T&/const T&、T&/T&&)提供默认支持;自定义类型必须显式特化 std::basic_common_reference 才能参与推导。
立即学习“C++免费学习笔记(深入)”;
怎么用 std::common_reference 推出迭代器的 reference?
别直接套 std::common_reference,先确认你的迭代器是否满足 indirectly_readable,再用标准约定:std::iter_reference_t<it></it> 是首选,它内部已整合了 std::common_reference 逻辑。
实操建议:
- 对单个迭代器类型
It,用std::iter_reference_t<it></it>,它会自动处理value_type、reference、pointer的一致性 - 对两个不同迭代器
It1,It2,需要它们解引用后类型可共引用,写成:std::common_reference_t<:iter_reference_t>, std::iter_reference_t<it2>></it2></:iter_reference_t> - 如果编译失败,大概率是其中一个迭代器没正确定义
reference成员(比如返回了void或裸值),或value_type不一致且无隐式转换
template<class It1, class It2>
using zip_reference = std::common_reference_t<
std::iter_reference_t<It1>,
std::iter_reference_t<It2>
>;为什么 std::common_reference_t 不总是 T const&?它确实通常是 const T&,但前提是 T 是完整类型、非 void、且未被显式禁用。容易踩的坑:
-
T 是不完整类型(比如在类定义体内提前使用),std::common_reference 无法实例化
-
T 是 void 或函数类型,标准禁止对其形成引用,推导直接 SFINAE 失败
- 你特化了
std::basic_common_reference 但忘了加 template<class...> class</class...> 参数包,导致匹配不到
- 编译器版本太低(GCC
性能影响几乎为零:这只是编译期类型计算,不生成运行时代码。但滥用会导致模板膨胀——比如在深度嵌套的 view 适配中反复推导,可能拖慢编译。
自定义类型怎么让它参与 common_reference 推导?
必须显式特化 std::basic_common_reference,不能靠 auto 或 deduction guide。
实操要点:
- 特化必须在命名空间
std 内,且针对具体 cv/ref 组合(如 T& 和 const U&)
- 第三个模板参数是
std::common_reference_t<t u></t> 的 fallback,通常设为 void 表示不支持
- 要同时特化所有你希望支持的组合,比如
T&/U&&、const T&/U& 等,否则推导链会断
namespace std {
template<class T, class U>
struct basic_common_reference<my_wrapper<T>&, my_wrapper<U> const&, T&, U const&> {
using type = my_wrapper<std::common_reference_t<T&, U const&>>&;
};
}复杂点在于:一旦开始特化,就得覆盖所有预期组合,漏一个就可能让整个 view 链失效;而且特化必须在所有使用前可见,头文件组织很容易出错。
它确实通常是 const T&,但前提是 T 是完整类型、非 void、且未被显式禁用。容易踩的坑:
-
T是不完整类型(比如在类定义体内提前使用),std::common_reference无法实例化 -
T是void或函数类型,标准禁止对其形成引用,推导直接 SFINAE 失败 - 你特化了
std::basic_common_reference但忘了加template<class...> class</class...>参数包,导致匹配不到 - 编译器版本太低(GCC
性能影响几乎为零:这只是编译期类型计算,不生成运行时代码。但滥用会导致模板膨胀——比如在深度嵌套的 view 适配中反复推导,可能拖慢编译。
自定义类型怎么让它参与 common_reference 推导?
必须显式特化 std::basic_common_reference,不能靠 auto 或 deduction guide。
实操要点:
- 特化必须在命名空间
std内,且针对具体 cv/ref 组合(如T&和const U&) - 第三个模板参数是
std::common_reference_t<t u></t>的 fallback,通常设为void表示不支持 - 要同时特化所有你希望支持的组合,比如
T&/U&&、const T&/U&等,否则推导链会断
namespace std {
template<class T, class U>
struct basic_common_reference<my_wrapper<T>&, my_wrapper<U> const&, T&, U const&> {
using type = my_wrapper<std::common_reference_t<T&, U const&>>&;
};
}复杂点在于:一旦开始特化,就得覆盖所有预期组合,漏一个就可能让整个 view 链失效;而且特化必须在所有使用前可见,头文件组织很容易出错。










