为何C++重载决议无法推导嵌套模板类型?
为什么C++禁止在可行场景下推导嵌套类型的模板参数?
有人指出的所谓重复问题只解释了该限制的机制及无法生效的极端场景,但未说明为何C++在可行场景下仍禁止该推导。
简而言之:我知晓C++无法实现此功能,也了解通过ADL的解决方法,并非询问该方法。我想知道的是,语言设计为何选择(或被迫)施加此限制。
详细说明:
以下代码除最后一种情况外均可正常运行:
template <class T> struct A { struct R {}; }; template <> struct A<double> { using R = int; }; void Fn(int); template <class T> void Fn(typename A<T>::R v); //////////////////////////////// void Test() { A<double>::R d; A<int>::R v; Fn(0); // Works; calls Fn(int) Fn(d); // Works; calls Fn(int) Fn(v); // Fails; expected to call Fn<int>(A<int>::R) }
最后一种情况失败的原因是,语言无法为Fn的模板重载推导模板参数T,以将typename A<T>::R解析为A<int>::R。对开发者而言,此处T显然应为int,但C++规则不允许该推导。
我的核心问题:
是什么原因促使或迫使C++设计者施加该限制?
我猜测答案可能是:在实际解析前“猜测”类模板包含嵌套类型存在技术或理念上的问题,或是现有编译器架构难以实现该逻辑。但只有前者是根本性问题,且我并不认为这些情况必然成立,这说明我遗漏了某些关键点。
顺便一提:除非Bjarne Stroustrup或90年代C++标准委员会成员看到此问题,否则最可能得到的是基于充分信息的推测性答案。
补充说明:
有多人指出,当A<R>::S以using别名(尤其是显式特化)提供时,最终解析后的完整类型可能完全不提及A<>。
- 这是合理的观点,但并非我所询问的场景。
- 这仅在“类型与类型别名在类型推导中必须被无差别对待”的假设下才相关。这可能是标准委员会的选择,而非被迫接受的结果。
- 即使在当前规则下,显式特化和类型别名也可能导致一些奇异且意外的结果,例如此示例:
template<int I> struct Int; template<> struct Int<0> { using T = int; }; template<> struct Int<1> { using T = long; }; template<int I> struct C { using T = typename Int<I % 2>::T; static int Mine(); friend int Get(T) { return C::Mine(); } }; void Test() { C<0> c0; // Ok C<1> c1; // This doesn't break anything. C<2> c2; // Delete this and things work. /* error: redefinition of 'int Get(C<2>::T)' note: 'int Get(C<0>::T)' previously declared here */ }
内容的提问来源于stack exchange,提问作者BCS
相关产品推荐
相关产品推荐

