Robotbugs
Robotbugs

Reputation: 4387

Correct use of templates for specific type-based optimization in C++ library

If I have a function that I want to implement for all types but then have specific optimizations for some types, how do I do this correctly in C++ with templates?

At the moment, in the header file I have:

template <class T> void Function(const T &src)
{
   printf("something generic to fall back on with src if nothing else fits");
}

void Function(const int &src);
void Function(const float &src);
void Function(const double &src);

Then in the cpp file I have:

void Function(const int &src) { printf("specialization %d\n", src); }
void Function(const float &src) { printf("specialization %g\n", src); }
void Function(const double &src) { printf("specialization %g\n", src); }

Firstly I wanted to check that I am correct in not putting template<> in front of the declarations in the header file? I don't fully understand the use of template with empty brackets.

Now it turns out that I have actually lots of cases of optimized implementations for about 10 different types. Some of them are almost the same, like the versions for float and double above. Therefore it makes sense if I can template a subset of the specializations that are within the cpp file, but I don't see how to do that. Is the only way to call a separate internal templated function?

What I want is a catch all implementation that is generic and is present in the header file which can be include by the application that uses the library, then I want a set of identical templated specializations for a subset of known data types that are exported from the library and implemented in the cpp file, and then finally a set of highly optimized cases for just one or two types that are also in the cpp file.

How can I best achieve this?

Upvotes: 1

Views: 117

Answers (2)

Mooing Duck
Mooing Duck

Reputation: 66922

You're 100% right that you don't need the template<> for this. You only need template when writing a template function, and you aren't writing template function specializations, you're making entirely new functions, that happen to have the same name.

//template function - templated on any type
template <class T> void Function(const T &src); 
//template function specialization for std::vector, itself takes 2 template params
//(This technically only works with classes, not functions, for unrelated 
// reasons, but it would use this syntax)
template <class U, class A> void Function<std::vector<U,A>>(const std::vector<U,A>& src);
//template function specialization for int, itself takes 0 template params
template<> void Function<int>(const int& src)

//not in any way a template, this is a completely unrelated regular function
void Function(double);

If you have nearly similar functions with different types, that calls 100% for templates! So use them! Note that since this template is only used in a single cpp file, it doesn't need to be in a header. The template itself can be in the cpp file. So, in your .cpp file, write this:

 template<class flttype>
 void FloatFunction(const flttype&src) {
     printf("specialization %g\n", src);
 }

 void Function(const float &src) { FloatFunction(src);}
 void Function(const double &src) { FloatFunction(src);}


You mentioned that these other function with the same name should be template specializations. That's not what you're doing, but that's also easy to do. In fact, it's surprisingly like regular functions. Change your prototypes to these:

template <class T> void Function(const T &src)
{
   printf("something generic to fall back on with src if nothing else fits");
}

template<> void Function<int>(const int &src);
template<> void Function<float>(const float &src);
template<> void Function<double>(const double &src);

and then change the code in your cpp files to these:

template<> void Function<int>(const int &src) { printf("specialization %d\n", src); }
template<> void Function<float>(const float &src) { printf("specialization %g\n", src); }
template<> void Function<double>(const double &src) { printf("specialization %g\n", src); }

Upvotes: 2

You don't need template specialization in your example: Overload resolution takes care of things for you.

Remember: When matches would otherwise be equal, non-template functions are preferred during overload resolution over template functions.

Therefore, for ints, the compiler will prefer the overload that explicitly takes an int (i.e. is not a template) to the one wherein it could deduce T to int and form a template match.

To try and clear up your confusion about template <>, you use it when you're declaring a specialized template, and you've specialized away all the template parameters. You can specialize function templates, but in many (perhaps "most") cases this is unnecessary and overloading (as you've done) is quicker and easier.

In your case, however, your non-template functions are not templates at all, so you're not specializing anything, and therefore you don't declare them as templates (empty parameter list or otherwise).

Upvotes: 1

Related Questions