Reputation: 2297
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.
Upvotes: 20
Views: 35294
Reputation: 113
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 );
}
Upvotes: 0
Reputation: 9089
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.
Upvotes: 23
Reputation: 1834
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.
Upvotes: 2
Reputation: 96241
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 string
s 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.
Upvotes: 13