为什么对重载函数模板的调用不存在二义性?

Igo*_*r G 6 c++ templates overload-resolution c++17

考虑以下示例。标记的行上有两个函数模板(1),并(2)在行上调用(3)。两个模板都与调用相匹配,并且似乎没有一个比另一个更专业。

#include <utility>

template <int V, bool Enabled = true>
struct Version;

template <int V>
std::true_type  Database(Version<V, V == 1>*);  // (1)

template <int V>
std::false_type Database(Version<V>*);          // (2)

using Winner = decltype(Database(std::declval<Version<1>*>()));  // (3)

int foo()
{
    return Winner::value;
}
Run Code Online (Sandbox Code Playgroud)

当然,我希望第 (3) 行会产生“不明确的调用”错误。但事实并非如此。gcc 13.2、clang 15.0 和 msvc v19.37 都选择重载 (2),没有错误。这是godbolt 在线示例

问题是:为什么?我在部分排序和重载解析中缺少什么?

Jar*_*d42 4

Function_template_overloading比较复杂,需要使用 Parameter/Argument 进行转换。

template <int V>
std::true_type  Database(Version<V, V == 1>*);  // #1

template <int V>
std::false_type Database(Version<V>*);          // #2


Database(std::declval<Version<1>*>()); // deduction for #1 [V=1]
                                       // deduction for #2 [V=1] 
// partial ordering:
 

// #1 from #2: Version<V, B> from Version<U, true>: P1=V, A1=U: V=U
//                                            P2=B, A2=true: B=true OK
 
// #2 from #1: Version<V, true> from Version<U, B2>: P1=V A1=U: V=U
//                                             P2=true A2=B2: fails
 
// #2 is more specialized than #1
Run Code Online (Sandbox Code Playgroud)

  • 这是转换的第一个要点:*“对于每个类型、非类型和模板参数,包括参数包,(自 C++11 起)生成唯一的虚构类型、值或模板,并将其替换为函数类型模板“*. 您可能会发现“T, T*”的示例,它变成“U1, U2*”。 (2认同)