0

I have a class template in which there is a function that takes an argument of the type of the class that inherits the template. I can't seem to find the right syntax to bring this about. For example, if this is my template:

// A template to promote a simple C-style struct, T_C, 
// to a C++ class 'T' with constructors, destructors, 
// copy and move assignment operators.
template <typename T_C> class myTemplate
{
    // We could in principle create templated copy and move  
    // constructors and assignment operators, but they'd be 
    // implicitly deleted by the compiler unless we explicitly defaulted 
    // them: see 
    // http://stackoverflow.com/questions/25246573/copy-assignment-operator-defined-in-template-being-deleted-by-compiler.
    // Explicitly defaulting them works well if the template is 
    // contained in an all-header library. However, on including
    // the template-derived classes into a DLL in Visual Studio 2013 
    // it was found that, even when all the other methods
    // in a class were properly exported, the defaulted 
    // template methods were not. There may be a workaround for
    // this, but in the scheme of things it was thought easier 
    // just to dispense with the templated operators and to
    // create copy and move assignment operators, as well as the 
    // corresponding constructors, for each derived type.
    //
    // We can at least simplify things a little, and force some 
    // consistency upon our various class definitions,
    // by insisting that every relevant class defines the 
    // functions listed, which can then be called from the
    // constructors and assignment operators to make them a bit 
    // more manageable.

    // Tidy up all pointers etc. and return all buffers to a safe state
    virtual void clear() = 0;

protected:
    // Construct a 'T' from a T_C:
    virtual void construct_contents(const T_C &source) = 0;

    // Deep copy the contents of a T_C to a 'T'
    virtual void copy_contents(const T_C &source) = 0;

    // Move the contents of one object to another: for use in both the move constructor 
    // and the move assignment operator:
    virtual void move_contents(myTemplate<T_C> &&source) = 0;
                               // For sure this is wrong, but I can't figure out 
                               // what the right argument type should be
};

...and this is my class

class myClass : public myStruct, public myTemplate<myStruct>
{
public:
    // Default constructor
    myClass() {}

    // Copy constructor taking basic C struct
    myClass(const myStruct &source)
    {  construct_contents(source);  }

    // Copy constructor taking this promoted C++ class
    myClass(const myClass &source)
    {  construct_contents(source);  }

    // Copy assignment operator taking basic C struct
    MyClass & operator=(const myStruct &source) 
    {
        copy_contents(source);
        return *this;
    }

    // Copy assignment operator taking this promoted C++ class
    MyClass & operator=(const myClass &source) 
    {
        copy_contents(source);
        return *this;
    }

    // Move constructor taking this promoted C++ class
    myClass(myClass &&source)
    {
        move_contents(std::move(source));
    }

    // Move assignment operator taking this promoted C++ class
    myClass & operator=(myClass &&source)
    {
         if (this != &source)
         {
            clear();
            move_contents(std::move(source));
         }
         return *this;
    }

    // Destructor
    ~myClass()
    {
        clear();
    }

    // Various getters and setters for the data fields of myStruct
    // ....

    virtual void clear() override
    {
        // Stuff...
    } 

protected:
    virtual void construct_contents(const myStruct &source) override
    {
        // Stuff...    
    }

    virtual void copy_contents(const myStruct &source) override
    {
        // Stuff...    
    }

    virtual void move_contents(myClass &&source) override
    {
        // Stuff...    
    }
};

...then everything works just fine except that the compiler throws an error saying (in Visual Studio 2013) 'member function declared with "override" does not override a base class member' when it encounters my definition of myClass::move_contents. I can understand why it is unhappy: 'myClass' is not only a 'myTemplate<myStruct>', but a type that jointly inherits both myTemplate<myStruct> and myStruct. What I actually need to do is to declare move_contents in the template so that the argument type is the same as the type of the derived object, in this case 'myClass'. However, I can't think of a way of specifying this in the template declaration.

My working solution is to take move_contents out of the template altogether and define a totally independent move_contents method for each separate derived type. This is all right, but doing this would block off the possibilty of pulling the move constructor and assignment operator back into the template - something I'd love to do if I can ever figure out a way of getting Visual Studio 2013 to export them properly.

Eos Pengwern
  • 1,467
  • 3
  • 20
  • 37

2 Answers2

1

The template parameter is myStruct, so the method expects an argument of type myTemplate<myStruct>, not myClass.

Declare your method with :

virtual void move_contents(myTemplate<myStruct> &&source) override
{
    // Stuff...    
}
quantdev
  • 23,517
  • 5
  • 55
  • 88
  • That gets me beyond the first hurdle, but not quite all the way; the next hurdle is that the move_contents method has to handle the various data objects that are components of myStruct. The entity 'myTemplate' has no access to these fields - that's precisely why 'myClass' needs jointly to inherit both 'myTemplate' and 'myStruct' itself. – Eos Pengwern Oct 29 '14 at 15:12
  • @EosPengwern : inheritance won't help you. If you need `myClass::move_contents` to access the `myStruct` content of the parameter, then `myTemplate` needs to store a `myStruct`, and expose it (or be a friend of `myClass`). – quantdev Oct 29 '14 at 15:17
  • Thank you, @quantdev: That's what I was afraid of; I don't want to make myTemplate (and hence myClass) store a myStruct when myClass already *is* a myStruct. I've been trying to figure out if there's a way of doing it using the friend syntax, but I haven't found one yet. I think I may need to stick with my original approach, that of taking move_contents out of the template altogether. – Eos Pengwern Oct 29 '14 at 15:44
0

I'm going to accept @quantdev's answer because he put me on the right track, but here is what eventually worked.

In my original code snippet (see my question above), I inserted an additional public virtual function into the template:

virtual T_C * baseObject() = 0;

In my definition of myClass, I overrode this as follows:

virtual myStruct * baseObject() override { return static_cast<myStruct *>(this); }

This worked because myClass inherits myStruct, so the 'this' pointer of any myClass object is always castable to a myStruct*.

Then, in my move_contents method, I was able to access the myStruct pointers to both the source and destination objects:

void move_contents(myTemplate<myStruct> && source) override
{
    stuff = source.baseObject() -> stuff;
    source.baseObject() -> stuff = nullptr;
                                   // So that the buffer which my new object now 
                                   // points to isn't released when the source 
                                   // object is destroyed
}

As far as I can see, this does everything that I need.

Eos Pengwern
  • 1,467
  • 3
  • 20
  • 37