namespaced class template inheritance in C++

2019-09-14 22:45发布

问题:

In an earlier question, I asked asked class template inheritance in C++.

I now have an extra level to add!

Consider the following code. (Assume the member definitions are present and accurate)

namespace Game
{
    namespace Object
    {
        template<typename T>
        class Packable
        {
        public:

            /**
             * Packs a <class T> into a Packet (Packet << T)
             * Required for chaining packet packing
             *************************************************/
            virtual sf::Packet& operator <<(sf::Packet& packet) = 0; // Work-horse, must be defined by child-class
            friend sf::Packet& operator <<(sf::Packet& packet, T &t);
            friend sf::Packet& operator <<(sf::Packet& packet, T *t);

            /**
             * Unpacks a <class T> from a Packet (Packet >> T)
             * Required for chaining packet unpacking
             *************************************************/
            virtual sf::Packet& operator >>(sf::Packet& packet) = 0; // Work-horse, must be defined by child-class
            friend sf::Packet& operator >>(sf::Packet& packet, T &t);
            friend sf::Packet& operator >>(sf::Packet& packet, T *t);

            /**
             * Unpacks a <class T> from a Packet (T <<= Packet)
             * Returns the <class T> for convienence
             *************************************************/
            //friend T& operator <<=(T t, sf::Packet& packet); // Returning reference to cut down on copying (they're already passing us our own copy)
            friend T& operator <<=(T &t, sf::Packet& packet);
            friend T* operator <<=(T *t, sf::Packet& packet);
        };
    }
}

And this Ship class inherits from Game::Object::Packable

class Ship : public Game::Object::Base<Ship>, public Game::Object::Packable<Ship>
{
    public:
        Ship( void );
        //...

        // For packing and unpackinng packets
        sf::Packet& operator <<(sf::Packet& packet);
        sf::Packet& operator >>(sf::Packet& packet);
}

What we're left with is the following error.

(null): "Game::Object::operator<<(sf::Packet&, Ship*)", referenced from:

I've come to the conclusion that it must have something to do with the use of namespaces. What is the solution to this if I wanted to retain the namespaces?

Here is an excerpt of the method definitions. Do I have to dereference the namespace? (I don't think that even means anything haha)

/**
 * Packs a <class T> into a Packet (Packet << T)
 * Required for chaining packet packing
 *************************************************/
template<class T>
sf::Packet& operator <<(sf::Packet& packet, T *t)
{
    // Call the actual one, but basically do nothing... this needs to be overrided
    return packet << *t;
}

template<class T>
sf::Packet& operator <<(sf::Packet& packet, T &t)
{
    // Call the pointer one, but basically do nothing... this needs to be overrided
    return packet << &t;
}

// ... other definitions etc.

回答1:

The friend declaration (non-template non-member) does not match the befriended function templates. I would advice you to provide the implementation inside the class definition:

    template<typename T>
    class Packable
        friend sf::Packet& operator <<(sf::Packet& packet, T &t) {
           return packet << t;
        }
    //...

This allows for a free non-template function that will be generated by the compiler on demand. Other alternatives include befriending the template or the template specialization that you care about.

Of course, you can ignore friendship completely and just provide the templates at namespace level, since they are implemented in terms of a public function…


Related:

  • https://stackoverflow.com/a/23718008/36565
  • https://stackoverflow.com/a/4661372/36565