views:

322

answers:

3

Is there a difference between defining member functions for a template class inside the class declaration versus outside?

Defined inside:

template <typename T>
class A
{
public:
    void method()
    {
        //...
    }
};

Defined outside:

template <typename T>
class B
{
public:
    void method();
};

template <typename T>
void B<T>::method()
{
    //...
}

For non-template classes, this is the difference between inlined and non-inlined methods. Is this also true for template classes?

The default for most of my colleagues is to provide definitions inside the class, but I've always preferred definitions outside the class. Is my preference justified?

Edit: Please assume all the above code is provided in the header file for the class.

+1  A: 

Yes, the exact same is true for template classes.

The reason why method definitions for template classes are usually preferred to be inline is that with templates, the entire definition must be visible when the template is instantiated.

So if you put the function definition in some separate .cpp file, you'll get a linker error. The only general solution is to make the function inline, either by defining it inside the class or outside with the inline keyword. but in either cases, it must be visible anywhere the function is called, which means it must typically be in the same header as the class definition.

jalf
Just out of curiosity, is the linker error universally true now? I know in the past some compilers provided different template instantiation options. The SGI Irix CC compiler, for example, defaulted to link-time instantiation and actually seemed to encourage putting template function definitions in their own .cpp file (i.e., not in header, non-inlined, not visible to calling code, just like any other non-inline function definition). Just wondering if inline template function definition has changed from being a compiler preference to a requirement of the language.
Darryl
@Darryl, you're describing extern templates. It's a non-standard extension, and not all compilers support it. The new standard, C++1x, is adding `extern` templates, though I believe it requires the keyword.
greyfade
Templates are compiled at each and every compilation unit that uses that particular instantiation, but they are 'weak' symbols (gcc terminology, I don't know how standard that is) and having the same symbol defined in more than one compilation unit will not be a link error. So there is no need to add the `inline` to template functions/methods. Another remark is that `inline` is a hint to the compiler, but it can be disregarded by the compiler (but it will affect how the symbols are created so that the linker won't complain about a double definition).
David Rodríguez - dribeas
+1  A: 

There's no difference, aside from having to type more. That includes the template bit, the inline and having to use more "elaborate" names when referring to the class. For example

template <typename T> class A { 
  A method(A a) { 
    // whatever
  } 
}; 

template <typename T> inline A<T> A<T>::method(A a) { 
  // whatever
} 

Note that when the method is defined inside you can always omit the template parameter list <T> when referring to A<T> and just use A. When defining it outside, you have to use the "full" name in the return type and in the name of the method (but not in the parameter list).

AndreyT
You're making "method" inline in both cases, which could be bad if the function body is large. That's what I'm trying to avoid.
Ben
The **inline** keyword has less to do with actually optimizing code, and more with whether multiple definitions of the same function are allowed or not. If a function is defined in a header (which is unavoidable with templates, or the case when a function is defined within a class declaration), and multiple compilation units include that, the linker will finally end up with multiple (identical) definitions of the same function/method. The **inline** keyword (which should be implicit with templates) tells the linker that it is OK, otherwise it would be a linker error.
UncleBens
The point is Ben that with a template you don't have any choice. It has to be marked inline or the template will not work. This is one reason some people dislike templates. Its also worth noting that the compiler doesn't actually HAVE to inline the thing it can do whatever it likes behind your back.
Goz
@Ben: I'm making it `inline` in order to obtain to *equivalent* declarations/definitions and thus better illustrate the fact that you need to type more in order to achive the same effect. If what you are trying to do is to obtain a non-inline method, you have no choice but to use the out-of-class definition. In that case, I don't understand why you are even considering (asking about) the in-class definition.
AndreyT
@Goz: Why does it *have* to be marked inline? No, it doesn't. The only reason I marked it `inline` is to make both declarations equivalent.
AndreyT
Because if you don't mark it inline its possible for it to get multiply defined as UncleBens describes ... You would be fine as long as the class doesn't get used with the same template parameter from 2 different CPP files I guess but thats not exactly "safe" behaviour ...
Goz
@AndreyT: Yes exactly, I'm trying to avoid everything becoming inline just because my colleagues didn't know better. Note that I didn't mark the out-of-class definition as inline in my example for exactly this reason. I'm asking about the in-class definition, because that's what my colleagues do, and I want to advise against this if there is a downside.
Ben
The *compiler* can only inline functions if it has the full definition (and the *linker*, if I'm not mistaken, may inline the rest), and with templates this is pretty much unavoidable. You can only trust your compiler to make good choices (it may choose not to inline functions even if they are marked with the **inline** keyword), and perhaps help it with the "optimize for size" option if you are not satisfied. Basically it is a non-issue, regarding code size, and where you implement the template method is largely a matter of taste (less clutter in class declaration vs more clutter total).
UncleBens
@AndreyT, @Goz: I believe that the `inline` keyword is optional for templates. Multiple definitions of a templated method in different compilation units will not produce a link error. The linker will disregard all but one of the definitions (it should also check for ODR violations, but no compiler I know of actually does it).
David Rodríguez - dribeas
@Goz: The one Diefinition Rule (ODR) for template functions is different from ODR for non-template functions. There's absolutely no problem with having multiple definitions of template functions. You don't need to worry about it at all. There's no need to make a template function definition inline even if you are declaring it in the header file, even if it is used in multiple CPP files. The problem you are describing does not exist.
AndreyT
@David Rodríguez: You are absolutely right. There's no need for the explicit `inline` here. The problem Goz seems to be describing does not really exist in C++.
AndreyT
My mistake ... not sure where I got that from ...
Goz
+1  A: 

Hi

I know this..I think it must be some what help full to u?

defining a member function outside of its template

It is not ok to provide the definition of a member function of a template class like this:

 // This might be in a header file:
 template <typename T>
 class xyz {
    void foo();
  };

// ...

 // This might be later on in the header file:
  void xyz<T>::foo() {
// generic definition of foo()
   }

This is wrong for a few reasons. So is this:

      void xyz<class T>::foo() {
         // generic definition of foo()
      }

The proper definition needs the template keyword and the same template arguments that the class template's definition was declared with. So that gives:

       template <typename T>
          void xyz<T>::foo() {
           // generic definition of foo()
                 }

Note that there are other types of template directives, such as member templates, etc., and each takes on their own form. What's important is to know which you have so you know how to write each flavor. This is so especially since the error messages of some compilers may not be clear as to what is wrong. And of course, get a good and up to date book.

If you have a nested member template within a template:

    template <typename T>
      struct xyz {
      // ...
      template <typename U>
       struct abc;
        // ...
       };

How do you define abc outside of xyz? This does not work:

     template <typename U>
    struct xyz::abc<U> { // Nope
      // ...
  };

nor does this:

 template <typename T, typename U>
 struct xyz<T>::abc<U> { // Nope
// ...
 };

You would have to do this:

     template <typename T>
       template <typename U>
           struct xyz<T>::abc {
            // ...
           };

Note that it's ...abc not ...abc because abc is a "primary" template. IOWs, this is not good:

// not allowed here: template template struct xyz::abc { };

BE Student