1

I've got this little utility class (templated) that I inherit throughout my project/classes.

The idea is that it allows for easy packing various members into and out of the class instances (for networking etc, not entirely important)

What I've got is as follows

    template<typename T>
    struct Packable
        /**
         * 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, const T *t)
        {
            // Call the actual one, but basically do nothing...
            return packet << *t;
        }

        friend sf::Packet& operator <<(sf::Packet& packet, const T &t)
        {
            // Call the actual one, but basically do nothing...
            return packet << &t;
        }

        friend sf::Packet& operator <<(sf::Packet& packet, T *t)
        {
            // Call the actual one, but basically do nothing...
            return packet << *t;
        }

        friend sf::Packet& operator <<(sf::Packet& packet, T &t)
        {
            // Call the actual one, but basically do nothing...
            return packet << &t;
        }
    };

What I'm trying to do, in short is make it so only one method needs to be specified/fleshed out in the child classes (denoted by the 'virtual' word).

What I want is to provide the other methods that take various forms of the class and just dereferences them as needed to use the virtual method that will exist when the classes are compiled.

Problem is that I seem to have created some infinite loops.

        friend sf::Packet& operator <<(sf::Packet& packet, T &t)
        {
            // Call the actual one, but basically do nothing...
            return packet << &t;
        }

Simply calls itself over and over. How do I dereference a reference into it's object?

Volte
  • 1,905
  • 18
  • 25
  • 1
    @RakibulHasan, `&t` is the address of the object `t` refers to. – chris May 27 '14 at 04:38
  • 1
    You have a recursive definition without an end condition. You should implement one of the operator. – Mohit Jain May 27 '14 at 04:38
  • @RakibulHasan ORLY ? [See it live](http://ideone.com/J2iZ0P). – WhozCraig May 27 '14 at 04:39
  • @MohitJain Yes... I have a recursive definition, as I stated in the OP. The question is, how do I fix this? I can't overload the << operator with a reference as virtual. – Volte May 27 '14 at 04:42
  • What do all these friend function have to do with the abstract **`Packable`** operator << member?. I see no indication *anything* is a **Packable** or derivation therein; just a bunch of friend methods operating with `sf:Packet`s. – WhozCraig May 27 '14 at 04:45
  • How the `virtual operator<<` is called? your definition is for `packable << packet`... but all the other references are `packet << T` – jsantander May 27 '14 at 04:49
  • I mean to say you are definining `operator <<` in terms of each other. Atleast one of them needs to have [independent definition](http://ideone.com/HHitVt). – Mohit Jain May 27 '14 at 05:23

1 Answers1

1

You have 4 overloads for operator << and they depend on each other.

  1. const T *, depends on 2
  2. const T&, depends on 1
  3. T *, depends on 4
  4. T&, depends on 3

So it is causing an endless recusion. You should implement at-least one of them as independent functionality and then rest of them dependent on this.

You can do it as shown below

template<typename T>
struct Packable
    /**
     * 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, const T *t)
    {
        // Call the actual one, but basically do nothing...
        return packet << *t;
    }

    friend sf::Packet& operator <<(sf::Packet& packet, const T &t)
    {
        // Call the actual one, but basically do nothing...
        //return packet << &t;

        // Serialize the contents into packet stream
        t.serialize(packet);
        return packet;
    }

    friend sf::Packet& operator <<(sf::Packet& packet, T *t)
    {
        // Call the actual one, but basically do nothing...
        return packet << const_cast<const T*>(t);
    }

    friend sf::Packet& operator <<(sf::Packet& packet, T &t)
    {
        // Call the actual one, but basically do nothing...
        return packet << &t;
    }
};

This function serialize should be implemented in each T type class or else you will see compile time error.

Mohit Jain
  • 30,259
  • 8
  • 73
  • 100
  • I want the virtual method `virtual sf::Packet& operator <<(sf::Packet& packet) = 0;` to be the workhorse (see the comment) that does the serialization. I want every other form of the class T to use that method. So if it's a pointer, dereference the pointer and call the method on it. If it's a reference, dereference the reference and call the method on it. Does that make sense? – Volte May 27 '14 at 14:32