0

To be consistent with other (non-template) functions in a class I wanted to define and invoke a friend template function.

I can define it with no problem (see function t below).

namespace ns{
struct S{
    void m() const{}
    friend void f(S const&){}
    template<class T>
    friend void t(S const&){}
};
template<class T>
void t2(S const& s){}
}

However later I am not able to invoke this t function in any way?

int main(){
    ns::S s;
    s.m();
    f(s);
//  t<int>(s); // error: ‘t’ was not declared in this scope (I was expecting this to work)
//  ns::t<int>(s); // error: ‘t’ is not a member of ‘ns’
//  ns::S::t<int>(s); // error: ‘t’ is not a member of ‘ns::S’
}

Even if it is not possible at all, I am surprised that I am allowed to define it.

I tested this with gcc 8 and clang 7.

alfC
  • 14,261
  • 4
  • 67
  • 118
  • 1
    Possible duplicate of [Overload resolution looking into namespaces](https://stackoverflow.com/questions/53393467/overload-resolution-looking-into-namespaces) – Jans Jan 12 '19 at 11:50
  • Or even more concrete https://stackoverflow.com/questions/2953684/why-doesnt-adl-find-function-templates – Jans Jan 12 '19 at 12:24

1 Answers1

1

What you need for this to work are a couple of forward declarations.

The below two lines of code should come before the namespace ns.

struct S; //Needed because S is used as a parameter in the function template
template<class T> void t(S const&);

And then this form of call will work inside main.

t<int>(s);

See demo here.

P.W
  • 26,289
  • 6
  • 39
  • 76
  • I find very strange that you can declare both `S` and `t` outside the namespace. How is that possible? (doing it inside the namespace seems possible but yet different). https://godbolt.org/z/fLFhNe – alfC Jan 13 '19 at 06:00
  • As per [class.name/2](https://timsong-cpp.github.io/cppwp/n4659/class.name#2), this is possible. "A declaration consisting solely of class-key identifier; is either a redeclaration of the name in the current scope or *a forward declaration of the identifier as a class name*. **It introduces the class name into the current scope.**". So you will no longer get the error: `‘t’ was not declared in this scope`. – P.W Jan 13 '19 at 13:41
  • I have been using c++ for a while and I still find this quite weird. – alfC Jan 14 '19 at 00:56