0

Why in the following the partial specialization is not selected by ADL?

template<class T>
void func1(T&){     // selected
    ...
}

namespace first{
    template<class R>
    struct foo{
       friend void func1<>(foo<R>&){        // expected
          cout << "foo.func1" <<endl;
       }        
    };      
} 

foo<int> f;
func1(f);   
Jans
  • 11,064
  • 3
  • 37
  • 45

2 Answers2

1

Template parameters are unrelated with friend declarations. You'll need to carry them disambiguated in thefriend declaration:

template<class R>
struct foo{
   template<typename U>
   friend void func1<U>(foo<U>&){
      cout << "foo.func1" <<endl;   // cat();
   }        
};      

Also for your case you should decide, if you want to put the friend definition inlined as above, or just provide a declaration:

template<class R>
struct foo{
   template<typename U>
   friend void ::func1<U>(foo<U>&);
};      

The latter should match the friend template function in the global namespace explicitly, and specialization can be made as necessary:

template<>
void func1(int&){
   // ...
}

template<>
void func1(std::string&){
   // ...
}

// a.s.o.
πάντα ῥεῖ
  • 1
  • 13
  • 116
  • 190
  • I believe your first example is ill-formed, ndr. – Barry Jul 15 '16 at 19:28
  • Thank's, separating friend declaration params from the template class param make it works. – Jans Jul 15 '16 at 19:28
  • @Barry, yes it is partially, but changing the part "func1" to "func1" and leaving the other parts as it is, fix the issue of "no partial specialization error" is this is what you refer. – Jans Jul 15 '16 at 19:30
1

You don't need to provide an specialization of func1. Just provide an overload:

namespace first {
    template <class R>
    struct foo {
        friend void func1(foo& ){
            std::cout << "foo.func1" << std::endl;
        }
    };
}

int i;
first::foo<int> f;

func(i);  // calls ::func<int>
func1(f); // calls first::func1(first::foo<int>& );

Otherwise, you can friend a specizliation, but you can't define a specialization in the class body:

template <class R>
struct foo {
    friend void func1<>(foo& ); // friends ::func1<foo<R> >
};
Barry
  • 286,269
  • 29
  • 621
  • 977
  • "but you can't define a specialization in the class body". @Barry if you look into the first scenario the specialization is made using foo& instead of foo& and the compilation fail because it can't find "cout" when linking but if instead you use "printf" the compilation succeed and friend specialization is chosen. – Jans Jul 15 '16 at 19:17
  • @xhamr 1) That's not a compile failure, that's a linker error 2) The code should fail to compile due to the explicit specialization... or at least would have ODR issues. Way simpler to overload. – Barry Jul 15 '16 at 19:23
  • @xhamr Sorry, doesn't have to fail to compile. See [\[temp.expl.spec\]](http://eel.is/c++draft/temp.expl.spec#6). – Barry Jul 15 '16 at 19:26