我有以下代码,可能看起来有些费解,但来自真实代码:
#include <iostream>
using namespace std;
template <class Hrm, class A>
void foo(Hrm& h, A& a)
{
cout << "generic" << endl;
}
template <template <bool> class Hrg>
void foo(Hrg<false>& h, int& a)
{
cout << "specialized int" << endl;
}
template <template <bool> class Hrg>
void foo(Hrg<true>& h, const int& a)
{
cout << "specialized const-int" << endl;
}
template <bool W>
struct what;
template<> struct what<true> { };
template<> struct what<false> { };
int main() {
what<true> wt;
what<false> wf;
int i = 5;
const int& ri = i;
foo(wt, i); // 1) generic
foo(wf, i); // 2) specialized int
foo(wt, ri); // 5) specialized const-int
foo(wf, ri); // 6) generic
return 0;
}
Ideone link。
我了解
4
:对于带有Hrg
的错误const int
,它没有专门的名称,因此将其称为通用版本。我的问题是,为什么在其他情况下需要调用给定的函数?
3
似乎称为专用const版本,因为const int
比A
更“直接”匹配。我想知道为什么会更具体地发生。而且,
1
和2
呢?特别是, 1
对我来说非常令人惊讶:为什么调用generic
版本而不是专用的const-int?附加说明:如果我将
foo
的两个特化更改为:template <template <bool> class Hrg>
void _foo(Hrg<false>& h, int& a)
{
cout << "specialized int" << endl;
}
template <template <bool> class Hrg>
void _foo(Hrg<true>& h, const int& a)
{
cout << "specialized const-int" << endl;
}
template <class Hrg>
void foo(Hrg& h, int& a)
{
return _foo(h, a);
}
template <class Hrg>
void foo(Hrg& h, const int& a)
{
return _foo(h, a);
}
然后输出变为:
foo(wt, i); // a) specialized const-int
foo(wf, i); // b) specialized int
foo(wt, ri); // c) specialized const-int
//foo(wf, ri); // d) compilation error
对我来说,这是一个更加直观的结果。
最佳答案
解决过载的步骤如下:
重要的是要记住,步骤4是在步骤3之后执行的; “通用性”或“模板性”是,仅是一条平局规则。
让我们在第一个代码块中查看所有示例。
(1)第一次和第三次重载成功扣除;不能第二次推导
Hrg
。因此,候选人是第一名和第三名(规则1)。两者都是可行的(规则2)。第一个重载会将i
绑定(bind)到int&
,而第三个重载将i
绑定(bind)到const int&
。首选与cv资格较弱的引用文献相结合(规则3)。 (Barry从标准中得到了具体的报价。)第一个(通用)重载获胜。(2)不能为第三次重载推导
Hrg
,因此它不是候选值(规则1)。第一个和第二个是候选人,并且是可行的(规则2)。第一个和第二个重载都完全匹配,无需进行任何转换,并且按规则3不能区分。第二个重载是因为它更专业(规则4)。(5)对于第二个重载,
Hrg
的推导失败,因此它不是候选者,而第一个和第三个重载是(规则1)。请注意,对于第一个重载,A
推导为const int
,产生与第三个重载相同的签名。它们都是可行的(规则2),在规则3的末尾是无法区分的。第三个重载是成功的,因为它更专业(规则4)。(6)对于第三个重载,
Hrg
的推导失败,因此它不是候选者,而第一个和第二个是(规则1)。第二次重载是不可行的(规则2),因为int&
无法绑定(bind)到ri
,即const
。第一个重载,即通用重载,是唯一可行的功能,因此胜出。我将重载分辨率留在第二个代码块中,作为读者的练习。
[1]作为T.C.在评论中指出,这里有一个微妙之处。打破平局规则仅适用于对于给定的一对功能,为每对对应的参数均等地对从参数初始化参数所需的隐式转换序列进行排序的情况。如果第一个函数对一个参数的隐式转换顺序更好,而第二个函数对不同参数的隐式转换顺序更好,则不采用平局决胜规则,并且保持歧义。但是,在问题的示例中不会发生这种情况。
关于c++ - C++如何考虑常量性,模板化性和泛型性来解析专用模板?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/30064094/