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