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

为何make_something<shared_ptr<int>>(nullptr)会匹配std::function重载?

为什么make_something<std::shared_ptr<int>>(nullptr)会匹配std::function重载?

要搞清楚这个问题,我们需要拆解重载决议的优先级规则和模板特化关系,结合每个调用的具体情况分析:

先明确两个重载的本质

我们有两个模板函数:

  1. 显式指定参数时变为右值引用的模板:

    template <class Type>
    void make_something(Type&& a)
    

    当显式指定Type为std::shared_ptr<int>时,参数类型是std::shared_ptr<int>&&(右值引用)。

  2. std::function专属模板:

    template <class Type>
    void make_something(std::function<Type()>)
    

    当显式指定Type为std::shared_ptr<int>时,参数类型是std::function<std::shared_ptr<int>()>。

逐个分析调用匹配逻辑

1. make_something<int>(1)

  • 第一个重载参数是int&&,1是int类型,属于精确匹配,无需任何转换。
  • 第二个重载需要将1转换为std::function<int()>,这是用户定义转换。
  • 精确匹配优先级远高于用户定义转换,所以选第一个重载。

2. make_something<int>(nullptr)

  • 第一个重载参数是int&&,nullptr是std::nullptr_t类型,无法转换为int(非指针类型不能从nullptr构造),因此第一个重载不可行。
  • 第二个重载可以通过std::function的nullptr_t构造函数,将nullptr隐式转换为std::function<int()>,所以只能选第二个重载。

3. make_something<int*>(nullptr)

  • 第一个重载参数是int*&&,nullptr可以标准转换为int*(nullptr_t到任意指针类型的转换是C++标准规定的),然后绑定到右值引用,属于标准转换序列。
  • 第二个重载需要将nullptr转换为std::function<int*()>,是用户定义转换。
  • 标准转换序列优先级高于用户定义转换,所以选第一个重载。

4. make_something<std::shared_ptr<int>>(nullptr)(核心问题)

这里两个重载都可行,但第二个被选中,原因有两点:

转换序列的优先级相同

  • 第一个重载:nullptr需要通过std::shared_ptr的nullptr_t构造函数转换为std::shared_ptr<int>(用户定义转换),再绑定到std::shared_ptr<int>&&(身份转换,属于标准转换的一部分),整体是用户定义转换序列。
  • 第二个重载:nullptr直接通过std::function的nullptr_t构造函数转换为std::function<std::shared_ptr<int>()>,也是用户定义转换序列。
  • 两者的转换序列优先级相同,此时需要看模板的特化程度。

模板特化程度决定优先级

C++重载决议中,当两个模板实例化后的函数都可行时,更特化的模板会被优先选中:

  • 第一个模板make_something(Type&&)是通用模板,可以接受任意类型的参数,泛化程度极高。
  • 第二个模板make_something(std::function<Type()>)是针对std::function类型的专属模板,泛化程度更低、更特化。
  • 因此,编译器会优先选择更特化的第二个模板,最终输出std::function overload。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 06:09:53