This code reproduces the problem with gcc-4.x, but compiles fine with prior
versions of gcc and with other compilers. The error output differs depending on
what exactly is parsed, but I believe this example illustrates the general
change in behavior. 

FILE: header1.h
------------------------------------------
#ifndef _INCLUDED_Header1_H
#define _INCLUDED_Header1_H

#include <string>

namespace N
{
    const std::string & resolveName(const int &)
    {
        static const std::string & name = "int";
        return name;
    }
    const std::string & getName(const int & v)
    {
        return resolveName(v);
    }

    template<typename ValueType>
        const std::string & getName(const ValueType & v)
    {
        return resolveName(v);
    }
}

#endif//_INCLUDED_Header1_H

------------------------------------------

FILE: main.cpp
------------------------------------------
#include <string>
#include "header1.h"

class A
{
public:
    A() { }
    ~A() { }
};

namespace N
{
    const std::string & resolveName(const A &)
    {
        static const std::string name = "A";
        return name;
    }
}

int main(int, char **)
{
    int result = 0;
    const std::string & resultName = N::getName(result);

    A a;
    const std::string & name = N::getName(a); // <- fails to find
N::resolveName(const A &)
    // while processing
    // template<typename ValueType> const std::string & getName(const ValueType
&) from
    // header1.h unless the above N::resolveName(const A &) is declared BEFORE
    // header1.h is included, though the point of resolution appears AFTER
    // both header1.h is included and N::resolveName(const A&) is defined.
    // This behavior is new to gcc-4 and not present in most other compilers
    // including gcc prior to version 4.

    return result;
}

------------------------------------------

g++ -c main.cpp
header1.h: In function &#8216;const std::string& N::getName(const ValueType&)
[with ValueType = A]&#8217;:
main.cpp:26:   instantiated from here
header1.h:21: error: invalid initialization of reference of type &#8216;const
int&&#8217; from expression of type &#8216;const A&#8217;
header1.h:8: error: in passing argument 1 of &#8216;const std::string&
N::resolveName(const int&)&#8217;


Changing main.cpp to include header1.h AFTER resolveName(const A &) is declared
works around this issue:

FILE: main.cpp
------------------------------------------
#include <string>

class A
{
public:
    A() { }
    ~A() { }
};

namespace N
{
    const std::string & resolveName(const A &)
    {
        static const std::string name = "A";
        return name;
    }
}

#include "header1.h"

int main(int, char **)
{
    int result = 0;
    const std::string & resultName = N::getName(result);

    A a;
    const std::string & name = N::getName(a); 
    return result;
}

------------------------------------------

In this contrived example, the workaround is straightforward and easy to
implement. In a larger codebase, the workarounds are difficult to implement or
even discern. I'm not sure what happens if there is some complex cyclic
dependency introduced now that parsing order is significant.

In my case specifically, I use namespaces to arbitrarily extend functionality
for client code as long as the user declares new methods in scope of the type
they are compiling. (e.g. serializing a complex, user-defined type).

Does the standard require this behavior, or is this an optimization that has
broken code that does not have gcc-4 correct ordering of its headers?


-- 
           Summary: template fails to resolve names even when the name is in
                    scope before the call point
           Product: gcc
           Version: 4.1.2
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: c++
        AssignedTo: unassigned at gcc dot gnu dot org
        ReportedBy: logicle at live dot com
 GCC build triplet: linux 2.6.23 x86_64
  GCC host triplet: linux 2.6.23 x86_64
GCC target triplet: linux 2.6.23 x86_64


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

Reply via email to