http://gcc.gnu.org/bugzilla/show_bug.cgi?id=47227
Summary: GCC ignores conversion function template specializatons if a derived class' conversion function converts to the same type Product: gcc Version: 4.6.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: c++ AssignedTo: unassig...@gcc.gnu.org ReportedBy: schaub.johan...@googlemail.com Unless I'm missing something, the following is ambiguous: template<typename T1, typename T2> struct A { }; struct base { template<typename T2, typename T1> operator A<T1, T2>(); }; struct derived : base { template<typename T1, typename T2> operator A<T1, T2>(); }; int main() { derived().operator A<int, int>(); } However, GCC always wants to take the derived class version. The reason for ambiguity is: A<param-#1#1, param-#1#2> is another type than A<param-#1#2, param-#1#1> (prior to deduction. When collecting candidates, 14.5.2/6 says: "A specialization of a conversion function template is not found by name lookup. Instead, any conversion function templates visible in the context of the use are considered. For each such operator, if argument deduction succeeds (14.8.2.3), the resulting specialization is used as if found by name lookup." In the context of the use, both functions templates are visible, so both are sent to argument deduction. Deduction will succeed, so *the specialization is used as if found by name lookup*. Name lookup cannot find declarations that are hidden, so this quite clearly requires the above to be ambiguous, and doesn't allow the base-class version to be "filtered out" later on. Hiding only takes place prior to deduction: template<typename T1, typename T2> struct A { }; struct base { template<typename T1, typename T2> operator A<T1, T2>(); }; struct derived : base { template<typename T1, typename T2> operator A<T1, T2>(); }; int main() { derived().operator A<int, int>(); } Now that is not ambiguous anymore, and will call the derived class version, because in the context of the use, the base-class version is hidden (12.3/5 and 3/8). Note that by constructing cases making the base-class version more specialized than the derived class version, we could actually make this a rejects-valid bug: template<typename T1, typename T2> struct A { }; struct base { template<typename T1, typename T2> operator A<T1*, T2>(); }; struct derived : base { private: template<typename T1, typename T2> operator A<T1, T2>(); }; int main() { derived().operator A<int*, int>(); } Comeau accepts this one just fine, while GCC rejects it, thinking the base-version is hidden.