Defining a function at its friend declaration of a class template means the definition will only be available once specializations of the class template are instantiated. If the signature of the function does not rely on a template parameter of the enclosing class template, the class template may only be instantiated exactly for one single specialization in each translation unit (implicitly inline, so different specializations in different translation units are fine, as long as the definition does not depend on the template parameter):

template<typename>
struct S {
    friend void f() {}
}; 

S<int> si{}; // f() definition instantiated
S<char> sc{}  // ODR-violation, [basic.def.odr]/1

In your example the friend declaration is different for each specialization of S, and you do not risk ODR, however at the point where you are asking for the address of the friend function, it is yet to be defined, as the class template has not yet been instantiated (for the S<256> specialization), and GCC correctly emits an undefined reference error.

This behaviour is quite well-known and can be (ab)used to circumvent private access rules via means of explicit instantiation definitions (and in C++20: explicit specialitions); see e.g. https://dfrib.github.io/a-foliage-of-folly/.

BR
David


Message: 3
Date: Thu, 05 May 2022 12:27:38 +0300
From: Vladimir Grigoriev <vlad.moscow@mail.ru>
To: Brian Bi <bbi5291@gmail.com>
Cc: std-discussion@lists.isocpp.org
Subject: Re: [std-discussion]  Templated entity: non-template friend
        function
Message-ID: <1651742858.636395871@f423.i.mail.ru>
Content-Type: text/plain; charset="utf-8"


Try this code

https://gcc.godbolt.org/z/Mrb3WzMv7

If to write

inline X< 256 >  operator +( const X< 256 >&,  const X< 256 >&)  noexcept ;

then the error message is

<source>:24: undefined reference to `S::operator+(S::X<256u> const&, S::X<256u> const&)'

You can meet me at http://cpp.forum24.ru/ or www.stackoverflow.com or http://ru.stackoverflow.com