18

I am aware that the syntax for declaring a template class method in a header and defining it in a source file goes as so:

myclass.h

template <typename T>
class MyClass {
  public:
    void method(T input);
  private:
    T privVar;
};

myclass.cpp

template <typename T>
void MyClass<T>::method(T input) {
    privVar = input;
}

But, what if the method is also a template? I am adding methods to the basic_string class, and I want to know how to write the implementation for the functions.

MyString.h

template <class _Elem   = TCHAR,
          class _Traits = std::char_traits<_Elem>,
          class _Ax     = std::allocator<_Elem>>
class String
    : public std::basic_string<_Elem, _Traits, _Ax> {
  private:
    // Types for the conversion operators.
    typedef       _Elem* _StrTy;
    typedef const _Elem* _ConstStrTy;

    //...

  public:
        // Conversion operators so 'String' can easily be
        // assigned to a C-String without calling 'c_str()'.
    operator _StrTy() const {
        return const_cast<_StrTy>(this->c_str());
    }

    operator _ConstStrTy() const {
        return this->c_str();
    }

    // ... Constructors ...

    /*------------ Additional Methods ------------*/

    //! Converts a value of the given type to a string.
    template <class _ValTy> static String ConvertFrom(_ValTy val);

    //! Converts a string to the given type.
    template <class _ValTy> static _ValTy ConvertTo(const String& str);
    template <class _ValTy> _ValTy ConvertTo(void) const;

    //! Checks if a string is empty or is whitespace.
    static bool IsNullOrSpace(const String& str);
    bool IsNullOrSpace(void) const;

    //! Converts a string to all upper-case.
    static String ToUpper(String str);
    void ToUpper(void);

    // ...
};

How could I implement template <class _ValTy> static String ConvertFrom(_ValTy val);? Because now not only do I need to specify the class template, but the function template too. I am betting the code I'm about to write isn't valid, but it should show what I am trying to accomplish:

MyString.cpp

template <class _Elem, class _Traits, class _Ax>
template <class _ValTy>
String<_Elem, _Traits, _Ax> String<_Elem, _Traits, _Ax>::ConvertFrom(_ValTy val) {
    // Convert value to String and return it...
}

I am not advanced at all with templates. Not only am I very doubtful that the above is valid, it seems cumbersome to write and not very readable. How would I go about implementing the template methods, and the static template methods which returns its own class type? Because I don't want to define them in the header.

Brandon Miller
  • 2,247
  • 8
  • 36
  • 54
  • 1
    You should probably read: [Why can templates only be implemented in the header file?](http://stackoverflow.com/questions/495021/why-can-templates-only-be-implemented-in-the-header-file). – Jesse Good Nov 12 '12 at 21:06
  • @JesseGood That shows me that there IS a way to implement a *normal* method from a template class in a source file separately, but not how to implement *templated* methods from a template class. Maybe I am overlooking something in the post, I don't want to be THAT guy. Should I just give up and go ahead and define the class methods inline in the header file? – Brandon Miller Nov 12 '12 at 21:13
  • If you are just trying to separate out prototypes from functionality for templates functions/classes you can try using the .inl paradigm: where the actual functionality is the .inl file, and you include that file at the end of your header file. – Alex Nov 12 '12 at 21:23
  • @BrandonMiller: When you say `inline in the header file`, do you mean inside the class? This is not the case, you can define template members outside the class in the header file or a separate implementation file, just **not** in a source file (only except if you explicitly instantiate them). – Jesse Good Nov 12 '12 at 21:39

4 Answers4

22

Syntax of definition of template member functions outside of template is like this:

template <class T> struct A
{
   template <class X> void f();
};

template<class T> template<class X> void A<T>::f()
{
}

So your code is correct.

Would like to note that defining template members in .cpp is not very useful. In this case you shall explicitly instantiate them with all types you need to use with this template. Or do not use them outside this .cpp which doesn't make sense.

Rost
  • 8,779
  • 28
  • 50
13

Before I answer your question, let me first say: Don't do this. Extend std::string by using free-functions instead, much like the standard library implements many algorithms. Additionally I'd suggest doing it for ranges rather than strings only but that's more subjective.

Also note that std::string avoids implicit conversions to C-strings not to make your life harder, but to protect your code from a wide variety of obscure bugs that can be caused by unexpected implicit conversions. I would think very long and hard about implementing them. Just think about this: It takes you a few extra moments to type.c_str() once when you write the code, and for the rest of eternity anyone who reads your code will immediately know that it's being used as a C-style string and not as a std::string.

To answer your question, just put the code in the header:

//! Converts a value of the given type to a string.
template <class _ValTy> static String ConvertFrom(_ValTy val)
{
    // Code here
}

Finally note that identifiers starting with underscore+capital letter (and many other things starting with _) are reserved for the compiler and thus all bets are off as to your program's functionality.

Mark B
  • 95,107
  • 10
  • 109
  • 188
2

Your function definition is valid, and it can't be defined outside of the class declaration in a less verbose way. Since you want to put the function definition in a .cpp file you can't take advantage of combining the function definition with the more concise function declaration. By putting the function definition in a .cpp file you will also have to explicitly instantiate all needed specializations of your template class.

Josh Heitzman
  • 1,816
  • 1
  • 14
  • 26
0

Below is an attempt to make an example code for Rost and Josh's answers:

template.hpp

#pragma once

template<class T>
class Add
{
public:
    T Addition(T summand1, T summand2);
};

void AddUsing( int summand1, int summand2 );

template.cpp

#include "template.hpp"
#include <iostream>

template<class T>
T Add<T>::Addition(T summand1, T summand2)
{
    return summand1 + summand2;
}

void AddUsing( int summand1, int summand2 )
{
    std::cout << Add<int>().Addition( summand1, summand2 ) << std::endl;
}

main.cpp

#include "template.hpp"

int main()
{
    AddUsing ( 2, 2 );
}
Vitalii
  • 53
  • 1
  • 7