Fed*_*dor 9 c++ templates partial-ordering language-lawyer overload-resolution
如果参数之一是占位符类型,则在非类型模板参数的情况下选择重载函数模板的规则是什么。我对编译器当前的行为感到困惑,请考虑下一个示例:
template<int N> struct A{};
template<auto... N> void f(A<N...>);
template<int N> void f(A<N>) {}
template<auto N> void g(A<N>);
template<int N> void g(A<N>) {}
int main() {
f( A<1>{} ); // ok in GCC and Clang, error in MSVC
g( A<1>{} ); // ok in GCC, error in Clang and MSVC
}
Run Code Online (Sandbox Code Playgroud)
这里 MSVC 无法在两组重载之间进行选择。另一方面,GCC总是选择类型更具体的函数模板<int>。Clang 有点处于中间位置,它<int>比参数 pack 更受欢迎,但它在和重载<auto...>之间的选择过程中发现了歧义。在线演示: https: //gcc.godbolt.org/z/4EK99Gjhx<int><auto>
哪一项行为是正确的或者标准没有明确规定?
这可能没有明确说明,但我们可以用部分排序规则来解释实现的一般行为。在[temp.func.order]中,据说
\n\n\n为了生成转换后的模板,对于每个类型、非类型或模板模板参数(包括其模板参数包),分别合成一个唯一的类型、值或类模板,并将其替换为函数类型中该参数的每次出现。模板。
\n[注1:为非类型模板参数合成的值的类型中替换占位符的类型也是唯一的合成类型。\xe2\x80\x94尾注]
\n
我突出显示了该注释,这明确表明转换后的模板g<auto>无效,因为A需要一个参数,但收到合成类型\xe2\x80\xa0int的值。\n因此,从模板到模板的推导有效,但无效反之亦然,因此被认为更专业。即我相信 Clang 是错误的。g<int>g<auto>g<int>g
因为我们有来自[temp.deduct.type]/9.2f的更简单的规则,它管理专业化的部分排序,并且即使在替换为时也会使可变参数重载更加专业化。autoint
\xe2\x80\xa0我在有关无效转换模板的措辞中找不到任何内容,只有 P0522 中的一个相关子句,它澄清了无效的重写形式导致重写模板至少不那么专业化(直观行为也是部分排序)。但即使我们假设它A可以接受任意类型的值,即它本身有一个auto参数,并且如果我们相应地调整代码,部分排序在 GCC 上仍然可以正常工作。
| 归档时间: |
|
| 查看次数: |
237 次 |
| 最近记录: |