7

I have a class Foo which is used in a small standalone project. It has a class definition in Foo.h with the implementation for the class' member functions in an implementation file Foo.cpp.

First question - one of the member functions of class Foo is a template method Foo::doSomething(), is it correct that the implementation of this method should appear with the declaration of the function in Foo.h ?

The template parameter which Foo::doSomething() will be instantiated with is one of two Functor types - class CalcA and CalcB.

Should I:

  • (A) put the defintion and implementation of the two Functor classes all together in Foo.cpp (where they are actually used by the implementation of other Foo member functions to call Foo::doSomething).
  • (B) put the definition and implementation of the two Functor classes in Foo.h.
  • (C) should I put split the definition and implementation of the two Functors across Foo.h and Foo.cpp as would be done with an ordinary class?
Macke
  • 24,812
  • 7
  • 82
  • 118
Paul Caheny
  • 1,281
  • 3
  • 11
  • 16

4 Answers4

8

General rule:

If foo::doSomething() is used outside foo.cpp (i.e. if it's public or protected, usually), it must go in the header.

If not, putting in in the cpp file is perfectly ok, and even a good idea (as it keeps the clutter away from the header file).

So, if the functors are only used in the cpp file, by all means put the template function there too. One can always refactor things later if this changes.

Macke
  • 24,812
  • 7
  • 82
  • 118
  • 1
    In the case where a template is needed in only one CPP file, then I would put the declaration and definition in just that file. If it is a member function template and the rest of the class is used in other translation units, I'd definitely put the definition in the .h file. I'd even be concerned about undefined or implementation-defined behavior if this wasnt done. – John Dibling Nov 30 '10 at 16:39
  • @Marcus, I should have mentioned that in the original question - yes Foo::doSomething() is a private template member function of class Foo. – Paul Caheny Nov 30 '10 at 19:25
  • 1
    @John, I don't follow your point, could you elaborate a bit? In my case I have a private template member function of class Foo, therefore it is only used by the implementation of class Foo in Foo.cpp. So that would seem to fit with the first case/sentence in your comment. But my situation also fits the description in the second sentence of your comment ("member function template and the rest of the class is used in other translation units") where you say to put it in a .h file. – Paul Caheny Nov 30 '10 at 19:43
  • @Czarak: My opinion is that you should by default put the definition of the member function template in th .h file in your case. @Marcus might disagree with me. You'll have to make a judgement call. – John Dibling Nov 30 '10 at 19:59
  • Even though its `private`, it seems a little risky & smelly to me to have not-completely-defined objects floating around different translation units. – John Dibling Nov 30 '10 at 20:01
  • I'm pretty pragmatic about undefined behavior in this case, and got 10 years of experience to back that up. An unseen member function implementation doesn't affect the object in any way, nor, given reasonable coding practices (match h/cpp files), can there be doubly-defined functions. OTOH, if you're writing nuclear power plant code, by all means, put it in the header. :) – Macke Nov 30 '10 at 20:44
  • @John Why would putting private definitions into the header file do any good? I don't understand what you mean by "it seems a little risky & smelly to me to have not-completely-defined objects floating around". People outside your .cpp TU can't call the private member template so you won't have any problem. You would just drag more dependencies and possibly otherwise unneeded #include files into the header for no good. – Johannes Schaub - litb Dec 01 '10 at 02:49
8

First you must understand templates mechanism. Templates are not compiled, they are instantiated when they are used and then their instantiation is compiled. So the compiler needs to have the full template definition in each module using the template function, in order to instantiate them first according to the parameters you've passed.

To solve your problem, there are three solutions but you'll see that they both lead to the same result. Either you implement your whole templates in your header file inside the class definition (we use to suffix them with .hxx instead of .h in order to precise they're containing templates definitions):

// Foo.hxx

#ifndef __FOO_HXX__
#define __FOO_HXX__

class Foo {
  public:
   template <class T>    
   void bar(const T& t) {
      t.doSomething();
   }
 };
#endif

Or you can externalize the definition from the class, but still in the header file:

// Foo.hxx

#ifndef __FOO_HXX__
#define __FOO_HXX__

class Foo {
    public:
       template <class T>    
       void bar(const T&);
};

template <class T>
void Foo::bar(const T& t) {
   t.doSomething();
}
#endif

Finally, you can implement template methods bodies in an external file (prefixed with .cxx for the same reason). It will contain methods' bodies but won't include "Foo.hxx". Instead, it's "Foo.hxx" that will include "Foo.cxx" after the class definition. This way, when the compiler resolves the #include directive, it finds the whole template definition in the same module, allowing it to instantiate it:

// Foo.hxx

#ifndef __FOO_HXX__
#define __FOO_HXX__
class Foo {
    public:
       template <class T>    
       void bar(const T&);
};

#include "Foo.cxx"

#endif

// Foo.cxx
template <class T>
void Foo::bar(const T& t) {
   t.doSomething();
}

The choice between these 3 ways to implement templates is rather a matter of readability (and taste).
Second and third are equivalent in terms of generated code, but I'd rather not use the cxx file solution, because it often leads to stupid errors when you forget to invert the include.

Moreover, well-known C++ libraries like STL or Boost propose their code in header files only, which is a sign of good design. By using external definition inside headers, you clarify the definition of your class. You also prevent the compiler to automatically inline methods, which can sometimes lead to poor results according to Herb Sutter http://www.gotw.ca/gotw/033.htm

jopasserat
  • 5,721
  • 4
  • 31
  • 50
  • thanks for the answer. I should have mentioned in my original question that the template member function in my situation is a private member function of class Foo. Seperately from that - given the three suggestions in your answer what are the advantages/disadvantages of each? The main difference I can see is that in your first suggestion the member function would be implicitly inline and in the next two it wouldn't, is that correct? What advantages/disadvantages do the second & third have over each other? – Paul Caheny Nov 30 '10 at 19:50
  • 1
    @Czarak: you're right -> methods defined in a class body are automatically inlined (see http://stackoverflow.com/questions/1443982/when-do-compilers-inline-c-code for more details about inlining). I edited my answer to add the precisions you asked. Hope it helped you. – jopasserat Nov 30 '10 at 22:39
1

My default would be to put the definition for the member function templates right in the .h file, like this:

class Foo
{
public: 
  template<typename T> void DoSomething(T t);
};

// ... later...

template<typename T>
void Foo::DoSomething(T t)
{
  // ...
}

If this is suboptimal for a particular case, then I'd take more heroic measures. Starting with #include-ing a .inc file with the definition at the end of the .h file, or possibly even doing explicit instantiations in the .cpp files where I needed the member function templates to be used.

John Dibling
  • 99,718
  • 31
  • 186
  • 324
1

The template method definition should indeed be in the header file of it the class it belongs to.

Like this:

class MyClass
{
    template <typename T>
    void foo(const T&)
    {
        // Definition
    }
};

Or like this (note that the template method definition can be included from separate file after the class declaration)

class MyClass
{
    template <typename T> void foo(const T&);
};

template <typename T>
void MyClass::foo(const T&)
{
    // Definition
}

The rest is depends on the style you agreed on and your needs.

I would put the functor declaration (or even the definition if they are simple) into the header if I use them not only in Foo or if Foo has them as class member.

Palmik
  • 2,675
  • 16
  • 13