Two files are appended at the end of this report: temp1.cc and temp2.cc. temp1.cc is the only file that causes a problem with recent releases of GCC. It contains :
1. a template definition of Structure<S> 2. a template definition of op_is_finite<S>(const Structure<S>*) 3. a template definition of algebra::AlphabetSet<L> inheriting from Structure 4. a template definition of Element<L> that calls op_is_finite(const algebra::AlphabetSet<L>*) in its ctor 5. a template overloaded definition for op_is_finite<L>(const algebra::AlphabetSet<L>*) 6. a main function that instantiate Element<char>. Because all definitions but main() are template, I expect the call to op_is_finite() in the ctor of Element<L> (#4) to be resolved during the instantiation of Element<char> (#6) after the second definition of op_is_finite() (#5) has been read. So the call would be bound to that second definition and not to the first. I have tested three GCC versions : g++-3.4 (GCC) 3.4.6 (Debian 3.4.6-6) g++-4.1 (GCC) 4.1.3 20070718 (prerelease) (Debian 4.1.2-14) g++-4.2 (GCC) 4.2.3 20071014 (prerelease) (Debian 4.2.2-3) Both 4.1 and 4.2 behave identically: they seem to ignore the second definition of op_is_finite and try to call the first. 3.4 does what we expect: it calls the second definition. We have found at least two ways to alter temp1.cc such that 4.2 will compile it. - One is to move the second definition of op_is_finite() (#5) before its use in the constructor of Element<L> (#4). This ordering would make sense to me if the functions were not template, but it's not clear why this would change anything in the resolution of template overloaded functions. I might be missing something. - Another possibility is to move AlphabetSet<L> struct out of the "algebra::" namespace. temp2.cc contains the updated code. I'm really surprized that 4.2 compiles temp2.cc without problem and fails on temp1.cc. ////////////////////////////////////////////////////// //////////////// temp1.cc starts here //////////////// ////////////////////////////////////////////////////// template<typename S> struct Structure {}; template<typename S> bool op_is_finite (const Structure<S>*) { // Error on purpose, this function is not expected to be instantiated. return Structure<S>(); } namespace algebra { template <typename L> struct AlphabetSet : public Structure<AlphabetSet<L> > {}; } template <typename L> struct Element { Element() { op_is_finite(static_cast<const algebra::AlphabetSet<L>*>(0)); } }; template <typename L> bool op_is_finite(const algebra::AlphabetSet<L>*) { // This is the function we want to be called. return true; } int main() { Element<char> alpha; } // % g++-3.4 -Wall -W temp1.cc // % g++-4.2 -Wall -W temp1.cc // temp1.cc: In function 'bool op_is_finite(const Structure<S>*) [with S = algebra::AlphabetSet<char>]': // temp1.cc:21: instantiated from 'Element<L>::Element() [with L = char]' // temp1.cc:34: instantiated from here // temp1.cc:7: error: cannot convert 'Structure<algebra::AlphabetSet<char> >' to 'bool' in return ////////////////////////////////////////////////////// //////////////// temp2.cc starts here //////////////// ////////////////////////////////////////////////////// template<typename S> struct Structure {}; template<typename S> bool op_is_finite (const Structure<S>*) { // Error on purpose, this function is not expected to be instantiated. return Structure<S>(); } template <typename L> struct AlphabetSet : public Structure<AlphabetSet<L> > {}; template <typename L> struct Element { Element() { op_is_finite(static_cast<const AlphabetSet<L>*>(0)); } }; template <typename L> bool op_is_finite(const AlphabetSet<L>*) { // This is the function that is called, as we expected. return true; } int main() { Element<char> alpha; } // % g++-3.4 -Wall -W temp2.cc // % g++-4.2 -Wall -W temp2.cc -- Summary: overloaded template function resolves differently if one type is included in a namespace Product: gcc Version: 4.2.3 Status: UNCONFIRMED Severity: normal Priority: P3 Component: c++ AssignedTo: unassigned at gcc dot gnu dot org ReportedBy: adl at gnu dot org GCC build triplet: i686-pc-linux-gnu GCC host triplet: i686-pc-linux-gnu GCC target triplet: i686-pc-linux-gnu http://gcc.gnu.org/bugzilla/show_bug.cgi?id=34073