转换函数模板参数推导在C中的含义
我无法理解C标准中转换函数模板参数推导规则的含义.该标准规定([temp.deduct.conv]第1条,N4594中的§14.8.2.3.1):
其中14.8.2.5([temp.deduct.type])是描述一般模板参数推导的部分(尽管最常见的情况是函数调用模板参数推导[temp.deduct.call],似乎不再指向那里;它永远?).然而,下一个条款让我感到困惑(第2条):
对我来说,这似乎意味着模板< class T>运算符T()和模板< class T>运算符T&()是相同的(并且指定两者都会导致歧义).但在我使用的任何编译器中都不是这种情况!例如: struct any1 { template <typename T> operator T() { } }; struct any2 { template <typename T> operator T&() { } }; void f1(int) { } void f2(int&) { } void f3(int const&) { } int main() { f1(any1()); // f2(any1()); compile time error f3(any1()); f1(any2()); f2(any2()); f3(any2()); } Live Demo 但是如果忽略引用,any1和any2应该具有相同的行为,对吧?显然他们没有,因为f2(any1())不能用gcc或clang编译,而f2(any2())用两者编译都很好. 下一个条款(第3条,特别是3.3)进一步混淆了一些事情:
这与关于删除引用的第2条一起,似乎意味着由于含糊不清,以下代码不应该编译: struct any3 { template <typename T> operator T&() { } template <typename T> operator T const&() { } }; void f1(int) { } int main() { f1(any3()); } Live Demo 然而,这对gcc和clang都很好. 我错过了什么? 编辑 我应该澄清一下clang和gcc编译器处理这个问题的方式正是我对C的一般(相对高级)理解的期望.一些评论者要求澄清我的困惑(并且隐含地说,为什么我应该关心).我在这里的困惑与试图理解标准的含义完全相关.我需要清楚地理解这一点,因为我提交的论文的代码很大程度上依赖于这项工作以及我对它的使用是否符合标准. 解决方法
您缺少的关键点是仍然必须进行重载解析.模板演绎不是故事的结尾.分别处理两个示例:
您引用的文字表明,对于两个转换运算符,T的推导是相同的,这是事实.但操作符本身并不相同.您还必须考虑绑定到引用的规则,这些规则在[dcl.init.ref]中枚举.该部分太长而不能简洁地复制,但这是一个错误的原因 f2(any1()); // error 与f2(1)是错误的原因相同:您不能将对非const的左值引用绑定到右值.因此,即使让两个操作符本身也不明确: struct X { template <class T> operator T(); // #1 template <class T> operator T&(); // #2 }; f1(X{}); // error: ambiguous f2(X{}); // ok! #1 is not viable,calls #2 f3(X{}); // ok! #2 is preferred (per [dcl.init.ref]/5.1.2)
就编译器而言,这是一个有趣的场景,因为gcc在这里有一个bug.两个候选人都应该是有效的(由于61663,gcc不认为#4有效).没有一个破坏者适用于确定最佳可行候选人,所以在这种情况下我们必须回到[temp.deduct.partial]来确定哪个候选人更专业化……在这种情况下,#4. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |