I have run into a compiler error with gcc 4.x that I am trying to understand
whether my code is wrong or the compiler has a bug.

FYI: 4.1.2 is shown in the compiler output below, but I have had the same
results with 4.2.1. The problem does not occur with gcc 3.4.1, 3.4.4, Borland
5.5, and Visual Studio 7 and 8.

The problem I am seeing is that gcc 4.x is unable to resolve which template
function should be used in certain contexts. I have tried to reduce the code
down to a small example that is included below. The problem boils down to one
template function calling another, as yet undefined template function, and then
not being able to resolve which template function definition should be called.

Another factor in this that I don't understand is that moving a class that is
used as a parameter to the function template out of a namespace eliminates the
issue.

In the example below, there are two template classes, Good_data and Bad_data,
with the only difference being that Bad_data is declared within a namespace.
There are also two template functions, early_function() and late_function(),
with the only difference being when they are defined relative to the template
functions they invoke.

>From the compiler output, early_function() fails to compile when used with
Bad_data, but is OK when used with Good_data. This is what drives me to the
conclusion that the compiler is not using template function definitions that
follow their usage. I have no idea why the namespace makes a difference.

Here is the code example followed by the compile info:

#include <iostream>

template <typename T>
class Good_data { // Lack of namespace allows this to work
    public:
        Good_data() :val() {}
        T get() const { return val; }
    private:
        T val;
};

namespace A { // Namespace injection causes failure
    template <typename T>
    class Bad_data {
        public:
            Bad_data() :val() {}
            T get() const { return val; }
        private:
            T val;
    };
}

// Forward declaration of template function.
template <typename T>
inline void display(const T& value);

// Problem shows up in this template function which
// uses display() prior to it being defined.
template <typename T>
void early_function(const T& value) {
    display(value);
}

// Default template function implementation
template <typename T>
inline void display(const T& value) {
    std::cout << value << std::endl;
}

// Template function specialization for Good_data.
template <typename T>
inline void display(const Good_data<T>& value) {
   display(value.get());
}

// Template function specialization for Bad_data.
template <typename T>
inline void display(const A::Bad_data<T>& value) {
   display(value.get());
}

// This function works apparently because specializations
// are defined prior to its definition.
template <typename T>
void late_function(const T& value) {
    display(value);
}

int main(int, const char* const) {
    Good_data<int> good;
    A::Bad_data<int> bad;

    early_function(good); // OK
    early_function(bad);  // Compilation error here with gcc 4.x!!!

    late_function(good); // OK
    late_function(bad);  // OK

    return 0;
}

Here is the compilation information:

Using built-in specs.
Target: i586-suse-linux
Configured with: ../configure --enable-threads=posix --prefix=/usr
--with-local-prefix=/usr/local --infodir=/usr/share/info
--mandir=/usr/share/man --libdir=/usr/lib --libexecdir=/usr/lib
--enable-languages=c,c++,objc,fortran,obj-c++,java,ada
--enable-checking=release --with-gxx-include-dir=/usr/include/c++/4.1.2
--enable-ssp --disable-libssp --disable-libgcj --with-slibdir=/lib
--with-system-zlib --enable-shared --enable-__cxa_atexit
--enable-libstdcxx-allocator=new --program-suffix=
--enable-version-specific-runtime-libs --without-system-libunwind
--with-cpu=generic --host=i586-suse-linux
Thread model: posix
gcc version 4.1.2 20070115 (prerelease) (SUSE Linux)

gcc --save-temps -c -g -Werror -W -Wall
../../../application/example/example.cpp
../../../application/example/example.cpp: In function âvoid display(const T&)
[with T = A::Bad_data<int>]â:
../../../application/example/example.cpp:33:   instantiated from âvoid
early_function(const T&) [with T = A::Bad_data<int>]â
../../../application/example/example.cpp:66:   instantiated from here
../../../application/example/example.cpp:39: error: no match for âoperator<<â
in âstd::cout << valueâ
/usr/include/c++/4.1.2/bits/ostream.tcc:67: note: candidates are:
std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT,
_Traits>::operator<<(std::basic_ostream<_CharT, _Traits>&
(*)(std::basic_ostream<_CharT, _Traits>&)) [with _CharT = char, _Traits =
std::char_traits<char>]
/usr/include/c++/4.1.2/bits/ostream.tcc:78: note:                
std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT,
_Traits>::operator<<(std::basic_ios<_CharT, _Traits>&
(*)(std::basic_ios<_CharT, _Traits>&)) [with _CharT = char, _Traits =
std::char_traits<char>]
/usr/include/c++/4.1.2/bits/ostream.tcc:90: note:                
std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT,
_Traits>::operator<<(std::ios_base& (*)(std::ios_base&)) [with _CharT = char,
_Traits = std::char_traits<char>]
/usr/include/c++/4.1.2/bits/ostream.tcc:241: note:                
std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT,
_Traits>::operator<<(long int) [with _CharT = char, _Traits =
std::char_traits<char>]
/usr/include/c++/4.1.2/bits/ostream.tcc:264: note:                
std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT,
_Traits>::operator<<(long unsigned int) [with _CharT = char, _Traits =
std::char_traits<char>]
/usr/include/c++/4.1.2/bits/ostream.tcc:102: note:                
std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT,
_Traits>::operator<<(bool) [with _CharT = char, _Traits =
std::char_traits<char>]
/usr/include/c++/4.1.2/bits/ostream.tcc:125: note:                
std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT,
_Traits>::operator<<(short int) [with _CharT = char, _Traits =
std::char_traits<char>]
/usr/include/c++/4.1.2/bits/ostream.tcc:157: note:                
std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT,
_Traits>::operator<<(short unsigned int) [with _CharT = char, _Traits =
std::char_traits<char>]
/usr/include/c++/4.1.2/bits/ostream.tcc:183: note:                
std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT,
_Traits>::operator<<(int) [with _CharT = char, _Traits =
std::char_traits<char>]
/usr/include/c++/4.1.2/bits/ostream.tcc:215: note:                
std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT,
_Traits>::operator<<(unsigned int) [with _CharT = char, _Traits =
std::char_traits<char>]
/usr/include/c++/4.1.2/bits/ostream.tcc:288: note:                
std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT,
_Traits>::operator<<(long long int) [with _CharT = char, _Traits =
std::char_traits<char>]
/usr/include/c++/4.1.2/bits/ostream.tcc:311: note:                
std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT,
_Traits>::operator<<(long long unsigned int) [with _CharT = char, _Traits =
std::char_traits<char>]
/usr/include/c++/4.1.2/bits/ostream.tcc:361: note:                
std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT,
_Traits>::operator<<(double) [with _CharT = char, _Traits =
std::char_traits<char>]
/usr/include/c++/4.1.2/bits/ostream.tcc:335: note:                
std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT,
_Traits>::operator<<(float) [with _CharT = char, _Traits =
std::char_traits<char>]
/usr/include/c++/4.1.2/bits/ostream.tcc:384: note:                
std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT,
_Traits>::operator<<(long double) [with _CharT = char, _Traits =
std::char_traits<char>]
/usr/include/c++/4.1.2/bits/ostream.tcc:407: note:                
std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT,
_Traits>::operator<<(const void*) [with _CharT = char, _Traits =
std::char_traits<char>]
/usr/include/c++/4.1.2/bits/ostream.tcc:430: note:                
std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT,
_Traits>::operator<<(std::basic_streambuf<_CharT, _Traits>*) [with _CharT =
char, _Traits = std::char_traits<char>]


-- 
           Summary: Template function resolution failure
           Product: gcc
           Version: 4.1.2
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: c++
        AssignedTo: unassigned at gcc dot gnu dot org
        ReportedBy: mpeuser at sandel dot com


http://gcc.gnu.org/bugzilla/show_bug.cgi?id=33951

Reply via email to