jac*_*k X 5 c++ templates partial-ordering language-lawyer c++17
最近,我发现GCC在偏序期间改变了行为,具体情况如下:
#include <iostream>
template<class T>
struct unknow_context{
using type = int;
};
template<class U>
void show(typename unknow_context<U>::type, U){ // candidate #1
std::cout<<"#1\n";
}
template<class T>
void show(int, T){ // candidate #2
std::cout<<"#2\n";
}
int main(){
show(0,0);
}
Run Code Online (Sandbox Code Playgroud)
结果是,Clang打印#2(任何版本Clang都打印出一致的结果)。但是,GCC具有不同的行为。旧版本的GCC打印#2,相反,最新的GCC抱怨候选函数不明确。让我们看看标准对偏序是怎么说的。
temp.deduct.partial#2
推导过程使用转换后的类型作为参数模板,使用另一个模板的原始类型作为参数模板。这个过程对偏序比较中涉及的每个类型进行两次:一次使用转换后的 template-1 作为参数模板和 template-2 作为参数模板,再次使用转换后的 template-2 作为参数模板和 template-1作为参数模板。
因此,我们可以分别得到候选#1和 的两组 P/A 对#2。一个是变换#1为A,原#2为P。另一个是原#1为P,变换#2为A。所以这两个集合如下:
#a
|--------|------------------------------------------|
| P (#2) | A (#1) |
|--------|------------------------------------------|
| int | typename unknow_context<UniqueA>::type |
|--------|------------------------------------------|
| T | UniqueB |
|--------|------------------------------------------|
Run Code Online (Sandbox Code Playgroud)
T可以推导出来UniqueB。对于第一组,规则说:
如果特定 P 不包含参与模板参数推导的模板参数,则不使用该 P 来确定排序。
所以,我们先把它们放在一边,稍后再考虑。
#b
|----------------------------------|-------|
|P (#1) |A (#2) |
|----------------------------------|-------|
| typename unknow_context<U>::type |int |
|----------------------------------|-------|
| U |UniqueA|
|----------------------------------|-------|
Run Code Online (Sandbox Code Playgroud)
对于非推导上下文,其值可以从别处获取。
然而,在某些上下文中,该值不参与类型推导,而是使用在其他地方推导或明确指定的模板参数的值。如果模板参数仅在非推导上下文中使用且未明确指定,则模板参数推导失败。
因此,我们可以忽略对typename unknow_context<U>::type/ int,而考虑U/ UniqueA。U可以推导出来UniqueA。
如果对给定类型的推导成功,则认为参数模板中的类型至少与参数模板中的类型一样专用。
从中#b,我们得到了#2至少与 一样专业的结果#1。
问题在#a set. 第二对没有问题,我们可以说 的第二部分#1至少和 的第二部分一样专业#2。
但是,函数模板 F 是否比函数模板 G 更专门化的规则定义为:
如果对于用于确定排序的每一对类型,函数模板 F 至少与函数模板 G 一样特化,则 F 中的类型至少与 G 中的类型一样特化。如果 F 位于,则 F 比 G 更特化至少与 G 一样专业,而 G 至少不像 F 那样专业。
因此,我们注意 pair int / typename unknow_context<UniqueA>::type,尽管规则说“P 不用于确定排序”。但是,标准中的一个重要说明是:
[?注:在[temp.deduct.call]和[temp.deduct.partial]下,如果P不包含出现在推导上下文中的模板参数,则不进行推导,因此P和A不需要具有相同的形式。?—?尾注?]
所以,就目前而言,从P/A set #a,#1至少还是和#2(演绎成功)一样专业。所以,我认为最新的GCC应该是正确的(模棱两可,两者都不比另一个更专业)。
哪个编译器是正确的?
是否在偏序期间执行特化的实例化?该标准似乎没有指定是否将执行实例化。
#a
|--------|------------------------------------------|
| P (#2) | A (#1) |
|--------|------------------------------------------|
| int | typename unknow_context<UniqueA>::type |
|--------|------------------------------------------|
| T | UniqueB |
|--------|------------------------------------------|
Run Code Online (Sandbox Code Playgroud)
都选择了#2。我很关心其中的特殊性P/A pair,即:
|----|------------------------------------------------------------|
|P |A |
|----|------------------------------------------------------------|
|T |typename unknow_context<UniqueA>::type /*Is it equivalent to|
| | UniqueA? */ |
|----|------------------------------------------------------------|
|T |UniqueA |
|----|------------------------------------------------------------|
Run Code Online (Sandbox Code Playgroud)
是否typename unknow_context<UniqueA>::type会被计算到UniqueA?似乎 All 编译器将其typename unknow_context<UniqueA>::type视为唯一类型,而不是将其计算为UniqueA.
| 归档时间: |
|
| 查看次数: |
89 次 |
| 最近记录: |