问题描述
在Functional programming in C++中,第11章介绍了一些基本的模板元编程。
在这种情况下,作者展示了remove_reference
/ remove_reference_t
的此实现,该实现与cppreference上描述的基本相同。
template<typename T> struct remove_reference { using type = T; };
template<typename T> struct remove_reference<T&> { using type = T; };
template<typename T> struct remove_reference<T&&> { using type = T; };
template<typename T> using remove_reference_t = typename remove_reference<T>::type;
参考上面的代码,作者评论说,“调用” remove_reference_t<int>
时,只有通用(或主要的?这里的校对词是什么?)模板成功地替代了T
,并且其他两个失败。这对我很清楚,无法将int
写为{\ {1}}或与T&
匹配。
关于T&&
,作者说第二个专业不能匹配。好吧,由于引用崩溃,难道不是一场比赛吗?我的意思是,如果我用remove_reference_t<int&>
代替T&&
,int&
就不能匹配T
,从而得到int&
吗?
类似地,在调用(为什么我会认为int&&& == int&
时,如果用remove_reference_t<int&&>
代替了T&
,则第一个专业化的int&&
是否不能匹配T
?int&
会倒塌为& &
而不是&&
?)
是什么使编译器放弃一种专业化?
解决方法
仅是通用模板(或主要模板?这里的正确单词是什么?)
C ++标准使用的技术术语是“主要类模板”。与它的部分专业化和显式专业化相比,它也是最通用的类模板。因此,在足够的上下文中,调用它也是合理的。
“引用折叠规则”在[dcl.ref]/6中找到,主要用于确定将引用类型别名为&
或&&
标记的特定类型名称组合的含义时使用通常会构成对类型名称类型的引用。推导形式为T&
或T&&
的模板参数的模板参数有点相反。尽管将模板自变量推论认为是“找到模板自变量以使结果类型匹配”是有帮助的,但是模板自变量推论的技术细节更为具体。 [temp.deduct]是几页规则,详细说明了扣除的进行方式,其他部分中还有其他相关规则。需要提供详细信息,以便编译器在可能会有多个“正确”答案的情况下达成共识,从而不需要编译器来处理一些较困难的情况。
尤其是,当将依存类型P
与已知类型A
匹配时,通过[temp.deduct.type]/8中的可推导类型列表,如果P
和A
的格式为T&
,或者两者的格式都为T&&
。尝试对部分专业化remove_reference<T&&>
进行自变量推导以确定remove_reference<int&>
的定义时,P
是T&&
,而A
是int&
,因此它们不共享其中一种形式。
模板自变量推导规则不具有从参考折叠规则的相反方向推导自变量的一般余地。但是对于某些情况,它们的配额确实有限:对于[temp.deduct.call]/3,如果T
是模板类型参数,但不是类模板的参数,则类型T&&
是转发引用。比较参数推论的类型时,如果P=T&&
是转发引用类型,而A
是左值引用类型,则可以将模板类型参数T
推导为左值引用类型{{ 1}},仅当A
是左值函数参数表达式的类型(再次是[temp.deduct.call] / 3)或有时要比较A
和P
时,它们代表两种比较函数类型([temp.deduct.type]/10)中的函数参数类型。
类似地,当[“] calling [”]
A
时,如果用remove_reference_t<int&&>
代替T&
,则第一专业化的int&&
不能与T
匹配。 ?
在这种情况下,局部特殊化T&
不可能与remove_reference<T&>
匹配。即使模板自变量推导过程允许找到这种情况的潜在答案,也不会存在remove_reference<int&&>
与T
相同的类型T&
。