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

std::make_pair类型推导原理及调用报错原因解析

关于std::make_pair的行为差异解析

先明确你的代码示例和问题:

std::vector<std::pair<int*, int*>> vec;
int* a = new int(1);
int* b = new int(2);
vec.emplace_back(std::make_pair(a, b)); // Fine
vec.emplace_back(std::make_pair<int*, int*>(&*a, &*b)); // Fine
vec.emplace_back(std::make_pair<int*, int*>(a, b)); // Error

报错信息:

GCC: cannot bind rvalue reference of type ‘int*&&’ to lvalue of type ‘int*’
Clang: no matching function for call to 'make_pair'

下面分点解析差异和原因:

一、std::make_pair的默认工作逻辑

当你不显式指定模板参数时,std::make_pair会做两件事:

  1. 自动推导传入参数的类型;
  2. 对推导得到的类型应用std::decay,最终用这个退化后的类型构造std::pair并返回。

std::decay的核心作用是把类型“标准化”为适合值传递的形式:去掉引用、cv限定符,数组转指针,函数转函数指针,确保pair存储的是可拷贝的基础值类型。

二、显式指定模板参数时的函数签名

std::make_pair的简化模板原型如下:

template <class T1, class T2>
constexpr std::pair<T1, T2> make_pair(T1&& t, T2&& u);

这里的T1&&和T2&&是转发引用,但转发引用的特性仅在模板参数自动推导时生效。一旦你显式指定T1和T2的类型(比如这里的int*),T1&&就会变成普通的右值引用(即int*&&),不再具备转发左值的能力。

三、逐行代码分析

1. std::make_pair(a, b)(无显式模板参数)

编译器推导a和b的类型为int*,经过std::decay后还是int*,所以返回std::pair<int*, int*>,和vector的元素类型完全匹配。同时,因为是自动推导模板参数,转发引用会识别a、b是左值,自动推导为左值引用类型,所以可以正常绑定左值参数,编译通过。

2. std::make_pair<int*, int*>(&*a, &*b)(显式指定模板参数)

显式指定模板参数后,函数参数要求是int*&&(右值引用)。而&*a的本质是:*a是左值int,取地址操作&*a得到的是一个临时的int*表达式——这是一个右值(没有名字的临时值),右值可以直接绑定到右值引用,因此编译通过。

3. std::make_pair<int*, int*>(a, b)(显式指定模板参数)

同样显式指定了模板参数,函数参数要求是int*&&。但a和b是有名字的变量,属于左值。C++规则明确禁止将非const的右值引用绑定到左值,因此编译器直接报错,这就是你看到的错误信息的来源。

四、std::decay的通俗理解

std::decay可以看作是类型的“降维处理”:

  • 对于引用类型:直接去掉引用(比如int*&→int*);
  • 对于带cv限定的类型:去掉const/volatile(比如const int*→int*);
  • 对于数组:转换成指向数组元素的指针(比如int[3]→int*);
  • 对于函数:转换成函数指针(比如void(int)→void(*)(int))。

它的存在是为了让std::make_pair返回的pair始终存储值类型,避免出现引用或数组等无法直接拷贝的成员。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.22 17:18:08