template specialisation

Started by
6 comments, last by NotAYakk 18 years ago
Template specialisation is basically when you write a function for specific behaviour for a type, right? I have a function that should only be called for the primitive types, primitive pointer types and std::string, std::string*. Will template specialisation be able to restrict the types used with this function to only these if I write a function for each?
[size="2"][size=2]Mort, Duke of Sto Helit: NON TIMETIS MESSOR -- Don't Fear The Reaper
Advertisement
Two ways you could accomplish this:

Using SFINAE:
boost::enable_if if boost is available in your project - requires boost
roll your own class with enable_if like functionality - could be a significant amount of work

Using function overloading:
In a header file declare funcitons prototypes for each of the tpyes you function should be callable for. In the corresponding source file, put your template function in the anonymous namespace, then implement each function prototype as a call to the template function.

i.e.:
//hppvoid addOne(char& data);void addOne(int& data);void addOne(unsigned int& data);//cppnamespace{    template < class T >    void addOne_impl(T& data)    {        ++data;    }}void addOne(char& data){ addOne_impl(data); }void addOne(int& data){ addOne_impl(data); }void addOne(unsigned int& data){ addOne_impl(data); }
Okay then.

Was I right about the template specialisation definition?
[size="2"][size=2]Mort, Duke of Sto Helit: NON TIMETIS MESSOR -- Don't Fear The Reaper
Quote:Original post by Endar
Template specialisation is basically when you write a function for specific behaviour for a type, right?

I have a function that should only be called for the primitive types, primitive pointer types and std::string, std::string*. Will template specialisation be able to restrict the types used with this function to only these if I write a function for each?


Why should it only be called for those types? What does it do? The whole point of templates is that you write generic code that can be used with any type that supports the operations you perform on it...
I've created an in-engine debug console which includes support for adding the addresses of variables outside the console and being able to access them inside the console at runtime. Pretty much all the primitive types except for char.

I'm using boost::variant to store pointers to all these variables, and visitors to get and set the values on the other end of the pointers.

I am using the function as a simple way to be able to add a pointer. I just started thinking that someone else who used this (or even me, it doens't really matter, it's probably good programming practice to at least think about these things) could attempt to add something more complex than a primitive type.
[size="2"][size=2]Mort, Duke of Sto Helit: NON TIMETIS MESSOR -- Don't Fear The Reaper
Quote:Original post by Endar
Template specialisation is basically when you write a function for specific behaviour for a type, right?


Yes and no.

Templates are used when you have a general algorithm that can be applied to all data types. You can use specializations to provide a variant of the algorithm for certain data types.

You can use template specialization to do what you're proposing by having the general case throw an exception at runtime and then specialize for all your supported types.

It's better to just use function overloading, though,because that will catch misuse at compile time, which is many orders of magnitude cheaper (at least, if other people use your software).

Stephen M. Webb
Professional Free Software Developer

Sure, you could use specialized function templates for seomthing like that. You could do something like the following:
template <typename Type>bool Foo(Type &rInst);template <typename Type>bool Foo(Type &rInst){  //If not a specialized template, not supported.  return false;}template <>bool Foo(int &rInst){  //do work...  return true;}template <>bool Foo(std::string &rInts){  //do work...  return true;}


basically specialize the function for all the types you want to support, and have supported types return true. Unsupported types will call the unspecialized function and return false.
If the code for most types is fundamentally differet, use overloads.

void foo(int);void foo(double);void foo(char const*);void foo(std::string<char>);

etc.

Templates on types are useful when the code with two different types is quite similar.

If the code for most types is similar, then try:
struct not_allowed {};struct allowed {typedef void check;};template<typename T>struct basic_types_only: not_allowed {};template<> struct basic_types_only<int>: allowed {};template<> struct basic_types_only<double>: allowed {};template<> struct basic_types_only<std::string<char> >: allowed {};template<> struct basic_types_only<char>: allowed {};// etctemplate<typename T>typename basic_types_only<T>::checkdo_work( T t ) {  // code goes here}


Then calling do_work for any type that isn't in the "allowed" list will fail.

But really, with a template, you can often "let the chips fall where they may" and simply have your code try to work with every type you pass it.

This topic is closed to new replies.

Advertisement