Friend declares a non-template function even though it resides in templated class (only gcc)

135 views Asked by At

The following example compiles BUT gcc warns me that the friend declaration is in fact not a templated function. I don't understand what exactly I'm supposed to change. Clang and MSVC accept this code without any issues.

In this this question it is implied that you're supposed to put template <typename T> in front of the in-class friend declaration, but then gcc complains about shadowing T.

Demo

#include <memory>
#include <cstdio>

/* header.hpp */

template <typename T>
class entity;

template <typename T>
auto create_entity() -> std::shared_ptr<entity<T>>;

template <typename T>
class entity
{
    // template <typename T>
    friend auto create_entity() -> std::shared_ptr<entity<T>>;
};

/* impl.cpp */

template <typename T>
auto create_entity() -> std::shared_ptr<entity<T>> {
    return std::make_shared<entity<T>>();
}

int main()
{
    create_entity<int>();
}

Warning:

<source>:16:41: warning: friend declaration 'std::shared_ptr<entity<T> > create_entity()' declares a non-template function [-Wnon-template-friend]
   16 |     friend auto create_entity() -> std::shared_ptr<entity<T>>;
      |                                         ^~~~~~~~~~~~~~~~~~~~~
<source>:16:41: note: (if this is not what you intended, make sure the function template has already been declared and add '<>' after the function name here)

How do I resolve this issue (for gcc)?

1

There are 1 answers

0
rustyx On

Identifiers used for template parameters may not be re-used inside the template for any other purpose. In other words, they may not be shadowed.

If you want any create_entity<U> to be a friend of entity<T>, change the inner T to U:

template <typename T>
auto create_entity() -> std::shared_ptr<entity<T>>;

template <typename T>
struct entity
{
    template <typename U>
    friend auto create_entity() -> std::shared_ptr<entity<U>>;
};

If you want only create_entity<T> to be a friend of entity<T>:

template <typename T>
auto create_entity() -> std::shared_ptr<entity<T>>;

template <typename T>
struct entity
{
    friend auto create_entity<T>() -> std::shared_ptr<entity<T>>;
};