函数模板重载解析混乱

Function template overloads resolution confusion

我想知道如何解决对 std::make_optional 的这两个重载的调用:

template< class T >
constexpr std::optional<std::decay_t<T>> make_optional( T&& value );

template< class T, class... Args >
constexpr std::optional<T> make_optional( Args&&... args );

我知道没有显式模板参数的调用如 make_optional(123) 会调用第一个,但是 make_optional<int>(123) 呢?将选择哪个重载,根据什么规则?

更新: 如果我写 make_optional<string>("hello world"),我将调用第二个重载(即使字符串文字可以隐式转换为 string), 正确吗?

过载解决方案首先确定可行的候选者,选择具有最佳转换顺序的候选者,然后查看决胜局列表。


make_optional(123) 只有一个可行的候选者,因为 T 是第二次重载中的非推导上下文。因此,它无疑是最可行的候选者。


make_optional<int>(123) 给了我们两个可行的候选者:

  • make_optional(int&& )[T=int]
  • make_optional<int>(int&& )[T=int, Args={int}]

该函数采用相同的参数 (int&&),因此它们在相同的转换序列下同样可行。第一个重载是比第二个重载更专业的函数模板(因为它采用单个参数而不是可变参数包),因此它是首选。


make_optional<string>("hello world") 给了我们两个可行的候选者:

  • make_optional(string&& )[T=string]
  • make_optional<string>(const char(&)[12] )[T=string, Args={const char (&)[12]}]

这里,这两个函数不采用相同的参数 - 第一个采用 string&&(这需要从字符串文字进行用户定义的转换),第二个采用 const char(&)[12](这是一个完全匹配)。因此,第二个重载具有更好的转换顺序并且是首选。