0

It's the first time I use Template on a class. Here's my attemp.

MyCairoControl.h:

#ifndef _MYCAIROCONTROL_
#define _MYCAIROCONTROL_

template<class T>
class MyCairoControl : public IControl 
{
private:
    T *pPlug;

public:
    MyCairoControl(T *plug, IRECT container);
    ~MyCairoControl();
};

#endif // !_MYCAIROCONTROL_

MyCairoControl.cpp:

#include "MyCairoControl.h"

MyCairoControl::MyCairoControl(T *plug, IRECT container) : IControl(plug, container), pPlug(plug) {
       // t->somethings();
}
MyCairoControl::~MyCairoControl() {

}

But it says "T" is undefined, so I can't use that CTOR. Isn't the right way to use template on a class?

markzzz
  • 47,390
  • 120
  • 299
  • 507
  • Something tells me you're going to be reading this sooner than later: ["Why can templates only be implemented in the header file?"](https://stackoverflow.com/questions/495021/why-can-templates-only-be-implemented-in-the-header-file) – WhozCraig Dec 06 '16 at 10:47
  • @paizza I have updated my answer for a brief discussion of using .cpp files with templates. It also works, now. – Xharlie Dec 06 '16 at 10:57

2 Answers2

3

Since MyCairoControl is a class template, its method definitions have to be templates as well, that match the class's template parameters:

template <class T>
MyCairoControl<T>::MyCairoControl(T *plug, IRECT container){
     /* ... */
}

template <class T>
MyCairoControl<T>::~MyCairoControl() { 
     /* ... */
}

wandbox example


This also means that the definitions always have to be available during compilation, not linking - they need to exist in the header file.

This article ("How to define a template class in a .h file and implement it in a .cpp file") gives a comprehensive explanation the issue.

Vittorio Romeo
  • 90,666
  • 33
  • 258
  • 416
  • I think the OP's bigger problem is the never-ending putting of template definitions in a separate source file. – DeiDei Dec 06 '16 at 10:48
  • @paizza: yes, that's pretty annoying... especially when you have multiple template parameters and when the methods are templated as well! A possible alternative is defining the methods inside the class *(in-place)*, which reduces some repetition but may make the code harder to read *(due to the lack of separation between interface and implementation)*. – Vittorio Romeo Dec 06 '16 at 10:50
  • If you know the types that might be used, you do not need to put the implementations in the header. – Xharlie Dec 06 '16 at 10:50
  • @VittorioRomeo; I don't understand what do you mean. Example? – markzzz Dec 06 '16 at 10:53
  • @paizza: [here's an example](http://stackoverflow.com/questions/7659322/how-to-define-template-function-within-template-class-in-inl-file) of the issue I mentioned. Here's [an example of in-place definition](http://melpon.org/wandbox/permlink/hYRHu3dds2vEwFmB). – Vittorio Romeo Dec 06 '16 at 10:54
  • About in-place definition: if I have other methods, and I define them in .cpp, I've the same trouble :O – markzzz Dec 06 '16 at 10:59
1

You need to redeclare T as a template type name in the implementation file:

#include "MyCairoControl.h"

template<class T>
MyCairoControl<T>::MyCairoControl(T *plug, IRECT container) : IControl(plug, container), pPlug(plug) {
       // t->somethings();
}


template<class T>
MyCairoControl<T>::~MyCairoControl() {

}

The original problem is two fold. Firstly, T as a symbol needs to be known as the template parameter. The template<class T> lines added to the implementation signatures does this - it defines what T means. Secondly, you need to realise that the type to which the constructor and destructor - and, indeed, any member - belongs is no longer MyCairoControl but MyCairoControl<T>. The left hand side of the scope-resolution operator now needs to be that.

There is a further concern to be noted. As it stands, the implementations of the class members are in a separate file from the header and this could present a problem. Consumers of the class will include the header and not the source file and so they will not be able to use the template - for example, if they try to use MyCairoControl<Foo> they will get unresolved symbol errors. This can be fixed if you know the types that will be used for T. Concretely, if you declare specialisations in MyCairoControl.cpp as follows:

template <>
class MyCairoControl<Foo>;

template <>
class MyCairoControl<Bar>;

Anyone will be able to use MyCairoControl<Foo> and MyCairoControl<Bar> but trying to use MyCairoControl<OtherType> will still give unresolved external symbol errors until you add a forward declaration for it, too.

Xharlie
  • 2,350
  • 3
  • 19
  • 39
  • Of course I've tried it, but it says `argument list for class template "MyCairoControl" is missing` around destructor... – markzzz Dec 06 '16 at 10:41
  • Sorry - I missed some bits - it is fixed. (Specifically: the parameter is for the class and must be on the class name, not only for the function. I misread the question.) – Xharlie Dec 06 '16 at 10:43