Clarification on template function specialization
-
27-09-2019 - |
Question
I want to create a calculator
template < typename T >
class Calculator
{
public :
Calculator ( void );
~Calculator ( void );
T add(T a, T b)
{
return ( a + b ) ;
}
};
Now I want to make this Caculator add strings, so add("Tim","Joe") shall give me "TimJoe" .
Can I use template function specialization for achieving this by making necessary changes to the existing class .
Solution
Why would you want to ?
Calculator<std::string> a;
std::cout << a.add("Hello", " world") << std::endl;
This code outputs "Hello world". It's not optimal (std::string
parameters in the add
member function are taken by value), but it does not require a specialization to work.
EDIT OK, you want specialization, but you can't just specialize the add
member function because the function is not template itself. You can either specialize the whole class :
template<>
class Calculator<std::string>
{
public :
Calculator() {}
~Calculator() {}
std::string add(const std::string &a, const std::string &b)
{
// Do std::string specific stuff
return a + b ;
}
};
Or make the add
member function template and specialize it :
class Calculator
{
public :
Calculator () {}
~Calculator () {}
template<class T>
T add(T a, T b)
{
return a + b;
}
};
template<>
std::string Calculator::add<std::string>(std::string a, std::string b)
{
// Do std::string specific stuff
return a + b ;
}
With the second solution, a single Calculator
instance will then be able to add int
, std::string
or whatever you need (as it's the add
function which is template, not the Calculator
class itself).
OTHER TIPS
If you use std::string
, then you won't have to deal with template specialization at all:
Calculator<std::string> calc;
std::string result = calc.add("Tim", "Joe");
// result contains "TimJoe"
This in fact does what you think it does thanks to the "magic" of the standard library, without having to write out another class.
I would, however modify your template class by making add()
accept parameters by const T&
:
template < typename T >
class Calculator
{
public :
Calculator() {};
~Calculator() {};
// Note that we're taking in parameters by const T&
// to avoid copies if instances of T are large.
T add(const T& a, const T& b)
{
return ( a + b ) ;
}
};
it is possible (even though it's not neccessary in this case for string as already mentioned by @icecrime and @In silico)
This is the way you could specialize your member function:
#include <iostream>
#include <string>
using namespace std;
template < typename T >
class Calculator
{
public :
Calculator () {}
~Calculator () {}
T add(const T& a, const T& b);
};
template <typename T>
T Calculator<T>::add(const T& a, const T& b)
{
return (a + b);
}
template <>
string Calculator<string>::add(const string& a, const string& b)
{
return (a + " " + b);
}
int main()
{
Calculator<string> ccs;
cout << ccs.add("a", "b") << endl;
Calculator<int> cci;
cout << cci.add(1, 2);
}
The output is:
a b
3
Notice, that it still behaves as you would expect, so you can not do for example this:
Calculator<int> cci;
cout << cci.add("a", "b");