Bug 29844 - Lookup of template dependent function fails in namespace
Summary: Lookup of template dependent function fails in namespace
Status: RESOLVED INVALID
Alias: None
Product: gcc
Classification: Unclassified
Component: c++ (show other bugs)
Version: 4.3.0
: P3 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2006-11-15 17:47 UTC by Ian Lance Taylor
Modified: 2021-09-02 01:05 UTC (History)
2 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Ian Lance Taylor 2006-11-15 17:47:22 UTC
I believe this short C++ code should compile without errors:

class c;
template<typename T> class tm { public: const T& g() const; };
namespace n {
  template <class T> int fn(const tm<T> &v) { return fn(v.g());  }
  int fn(const c *p);
}
int main() { tm<c *> v; return n::fn(v); }

Instead, I get

foo.cc: In function ‘int n::fn(const tm<T>&) [with T = c*]’:
foo.cc:7:   instantiated from here
foo.cc:4: error: no matching function for call to ‘fn(c* const&)’

Here fn is being called recursively with an argument which depends on the template type, so it should be looked up at template instantiation time, not at template definition time.  So the matching call should be found.

By comparison, this code compiles without error:

class c;
template<typename T> class tm { public: const T& g() const; };
namespace n {
  int fn(const c *p);
  template <class T> int fn(const tm<T> &v) { return fn(v.g());  }
}
int main() { tm<c *> v; return n::fn(v); }

This is not surprising, since the function declaration can now be seen at template definition time.

However, this code also compiles without error:

class c;
template<typename T> class tm { public: const T& g() const; };
template <class T> int fn(const tm<T> &v) { return fn(v.g());  }
int fn(const c *p);
int main() { tm<c *> v; return fn(v); }

Here the declaration is only available at template instantiation time, yet it works.

So it seems to be me that there may be a bug related to namespaces when handling lookup of template dependent types.  I haven't investigated further.
Comment 1 Andrew Pinski 2006-11-15 18:10:47 UTC
I don't think this is a bug.
There are two clauses to the C++ standard about namelookup in templates.
One applies where the definition.
And the other applies to both definition and instaination but only for the namespace containing the type.

Take the first case:

class c;
template<typename T> class tm { public: const T& g() const; };
namespace n {
  template <class T> int fn(const tm<T> &v)
  {
   return fn(v.g());
    // we have one overloading function for fn, the current template fn
    // at definition
  } 
  int fn(const c *p); 
}
int main()
{
  tm<c *> v;
  return n::fn(v);
    // when instationating this function fn, we look again at the overloading
    //  set for fn but since c is defined in the global namespace, we don't see
    //  the other fn in namespace n.
}


PR 2922/DR 197 describes this better than I can right now.
Comment 2 Andrew Pinski 2006-11-16 04:02:27 UTC
This is not a bug.
14.6.4.2 Candidate functions
For a function call that depends on a template parameter, if the function name is an unqualified-id but not a template-id, the candidate functions are found using the usual look rules (3.4.1, 3.4.2) except that:
-- For the part of the lookup using unqualified name lookup (3.4.1), only functions with external linkage from the template __DEFINITION__ context are found
-- For the part of the lookup using associated namespaces (3.4.2), only functions declarations with external linkage found in either the template __DEFINITION__ context or the template __INSTANTIATION__ context are found.


__BOLD__ is mine.

So what this says that the functions that are chosen for this fn (in the first case) is either the template fn or a function which is associated with the namespace of the type, which is in this case is the global namespace (ADL does not look into nested namespaces).

That explains the first case.

The second case can be explained by this:
the function fn is seen at the template __DEFINITION__ context which makes it valid code.

The third case can be explained by this:
The namespace associated with the type is the global namespace and there is a function fn that matches the arguments in that namespace at the template __INSTANTIATION__ context.

Hopefully this explains why the first case is invalid code and why the rest are valid.

One should note there is no associated namespace for fundumental types at least not yet, there is a Defect report about this to the C++ standard raising from DR 197.