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

std::make_pair与std::pair的区别及std::ref被忽略问题解析

std::make_pair与std::pair的差异

咱们先把这两个工具的核心区别拆解清楚:

  • 类型推导的灵活性不同:
    用std::pair的时候,你必须手动指定模板参数,比如std::pair<int, std::string> my_pair(1, "foo");;而std::make_pair会自动推导传入参数的类型,不用你写模板参数,比如auto my_pair = std::make_pair(1, "foo");,编译器会帮你推导出这是std::pair<int, const char*>(如果要转成std::string,你得显式把字面量转成std::string)。

  • 处理引用类型的逻辑完全不同:
    这也是你第二个问题的核心——std::make_pair默认会对参数做**类型退化(decay)**处理:它会把引用、数组、std::reference_wrapper这些类型自动转换成对应的普通值类型或指针。比如你传std::ref(x)给make_pair,它会把std::reference_wrapper<T>直接解包成T,生成值类型的pair元素;但如果你用std::pair,可以显式指定引用模板参数,比如std::pair<int&, int> my_pair(std::ref(x), 5);,这样就能保留对x的引用。

  • 语法简洁性差异:
    当参数类型比较复杂时,make_pair写起来更省心,不用重复写两遍冗长的模板参数,代码会更简洁清爽。

  • 隐式转换的处理不同:
    比如你有一个派生类对象想存成基类类型的pair,用std::pair<Base, int> my_pair(Derived(), 1);可以直接隐式转换;但make_pair会推导成std::pair<Derived, int>,如果需要基类类型,你得显式转换或者手动指定make_pair的模板参数。

为什么std::make_pair会“忽略”std::ref导致输出3412?

先给你说清楚背后的核心逻辑:std::make_pair的模板参数推导是基于std::decay规则的,而这个规则会自动把std::reference_wrapper(也就是std::ref返回的类型)解包成原始的对象类型,而不是保留引用或者reference_wrapper本身。

举个例子,如果你写:

Test t{1};
auto p = std::make_pair(std::ref(t), 5);

这里p的类型是std::pair<Test, int>,而不是你预期的std::pair<Test&, int>——也就是说,pair里存的是t的副本,而不是对t的引用,看起来就像是std::ref被“忽略”了。

回到你的代码场景:你原本可能希望通过std::ref让pair里存储Test对象的引用,这样后续修改原对象时,Callback调用的是最新的值;或者反过来,你希望存副本,结果因为make_pair的解包逻辑,Callback实际绑定了原对象的引用。不管哪种情况,输出3412的原因都是make_pair没有按照你预期的保留std::ref的引用语义,而是生成了值类型的元素。

如果想要让pair保留引用类型,你有两个解决办法:

  1. 直接用std::pair并显式指定引用模板参数:
    std::pair<Callback, Test&> my_pair(callback, std::ref(test_obj));
    
  2. 给std::make_pair显式指定模板参数,强制它保留引用:
    auto my_pair = std::make_pair<Callback, Test&>(callback, std::ref(test_obj));
    

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 03:53:55