多个部分专用化与模板参数列表匹配
more than one partial specialization matches the template argument list
当我运行下面的程序时,我收到一个错误,说有多个专业化与类X<int,int*,10>。编译器显然不能决定是否使用";专业化1";或";专业化2";。我不明白为什么会出现这种情况,因为我认为编译器根据模板参数的数量来确定专业化级别。因此,由于";专业化1";具有2个模板参数(template<class T, int I>
(;专业化2";只有1个模板参数(template<class T>
(;专业化2";比";专业化1";。显然,我的推理是不正确的,那么有人能解释推断哪个模板更专业背后的逻辑吗?
#include <iostream>
using namespace std;
template<class T, class U, int I> struct X {
void f() { cout << "General Template" << endl; }
};
template<class T, int I> struct X<T, T*, I> {
void f() { cout << "Specialization 1" << endl; }
};
template<class T> struct X<int, T*, 10> {
void f() { cout << "Specialization 2" << endl; }
};
int main() {
X<int, int*, 10> f;
f.f();
return 0;
}
不幸的是,这个主题非常复杂!我是基于这个答案和cppreference,同时引用该标准的当前工作草案。
首先,根据";部分专业化的匹配":
如果部分专门化的模板参数可以从实际模板参数列表推导出来,并且推导出的模板参数满足部分专门化(如果有的话(的相关约束,则部分专门化与给定的实际模板参数表匹配。
在您的示例中,上下文是语句X<int, int*, 10> f;
,它匹配两个部分专用化:
template<class T, int I> struct X<T, T*, I> {...} // -> T = int, I = 10
template<class T> struct X<int, T*, 10> {...} // -> T = int
既然是这样,就需要进一步检查,以确定这些候选人中的一个是否比另一个更专业。这在";部分专业化的部分排序":
对于两个部分专业化,第一个比第二个更专业化如果对两个函数模板进行以下重写,根据函数模板的排序规则,第一个函数模板比第二个子模板更专业化:
- 这两个函数模板中的每一个都具有与相应的部分专门化相同的模板参数和相关约束
- 每个函数模板都有一个函数参数,其类型为类模板专用化,其中模板参数是部分专用化的简单模板id的template argument list中每个模板参数的函数模板中的相应模板参数
这很冗长,但正如示例所示,它只是将部分专业化写为函数参数:
template<class T, int I> void f(X<T, T*, I>); // #1
template<class T> void f(X<int, T*, 10>); // #2
从那里我们必须看到关于";函数模板的部分排序";。引用相关段落:
偏序通过依次转换每个模板(见下一段(并使用函数类型执行模板参数推导来选择两个函数模板中哪一个比另一个更专业。[…]
为了生成转换后的模板,对于每个类型、非类型或模板模板参数(包括其模板参数包(,分别合成一个唯一的类型、值或类模板,并将其替换为该参数在模板的函数类型中的每次出现。
使用转换后的函数模板的函数类型,对另一个模板执行类型推导,如[temp.dexecute.partial]中所述。
换句话说,将#1和#2(再次(变换为"0";实例化";每个都有唯一的自变量,也就是说,不同于任何其他存在的自变量:
void f(X<Ut1, Ut1*, Uv1>); // #A
void f(X<int, Ut2*, 10>); // #B
然后使用他们的";"函数类型";,作为返回类型和参数类型,根据另一个部分执行推导,";在部分排序期间推导模板参数":
推导过程使用转换后的类型作为参数模板,另一个模板的原始类型作为参数模版。对于偏序比较中涉及的每个类型,此过程要执行两次:一次使用转换后的模板-1作为参数模板,模板-2作为参数模板;另一次使用转化后的模板-2作为自变量模板,模板-1作为参数模板。
好的,通过cppreference上的示例:
// #1 from #B:
// void(X<T, T*, I>) from void(X<int, Ut2*, 10>): deduction fails
// #2 from #A:
// void(X<int, T*, 10>) from void(X<Ut1, Ut1*, Uv1>): deduction fails
至少,我认为是这样的,因此整个磨难的结果是,两个模板都比另一个模板更专业。
- 概念中的cv限定符需要表达式参数列表
- 在没有参数列表的情况下使用模板名称"Event"无效,模板问题
- 错误 没有与参数列表匹配的重载函数"getline"实例
- std::vector 没有重载函数的实例与参数列表匹配
- 模板参数列表中的 false 在模板初始化期间计算为什么?
- C++模板/别名 - 模板参数列表中参数 1 处的类型/值不匹配
- 构造函数/函数声明参数列表中的统一初始化
- 模板化检查是否存在带有参数列表的类成员函数?
- 如何将类成员方法的参数列表自动填充写入可变参数?
- 带有整数的变量参数列表
- 转发变量参数列表以模拟 std::thread
- 错误:"模板<类_Tp,类_Dp>类 std::unique_ptr"的模板参数列表中参数 1 的类型/值不匹配
- C++-将具有引用的长参数列表重构为结构
- 缺少别名模板C++参数列表
- C++如果两个模板函数都与参数列表匹配,将调用哪个模板
- "extern"声明以及带有和不带参数列表的类模板实例的后续定义
- 使用显式模板参数列表和 [temp.arg.explicit]/3 的函数调用的演绎失败
- 没有函数模板的实例与我不知道为什么的参数列表匹配
- 我可以使用宏自动构建参数列表吗?
- 类成员函数参数列表是否可以依赖于模板参数?