Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Partial specialising function template with templated argument

I've got a template function (for the sake of simplification, let's call it "add")

template<typename T>
inline T add(const T a, const T b)
{
    return a+b;
}

I can specialise it for certain types, but what I'd like to do is specialise it for a templated type.

In my case, my templated type is called Vec2<T>. It's a 2-dimensional trigonometric vector (as in x & y, rather than c++ vector!)

What I'd like to do is specialise my add function for the generic case of Vec2<T>, rather than have to specialise for each type that Vec2 may be used with.

The library that Vec2<T> comes from has typedefs for V2d (double), V2f (float) and V2i (int).

I can specialise for each of these using something like:

template<>
inline V2f add<V2f>(const V2f a, const V2f b)
{
    return V2f(a.x + b.x, a.y + b.y);
}

However, what I'd like to be able to do, and this is where I've found myself stuck, is something like:

template<typename S>
inline Vec2<S> add<Vec2<S> >(const Vec2<S> a, const Vec2<S> b)
{
    return Vec2<S>(a.x + b.x, a.y + b.y);
}

I feel like there must be a way of doing this, but I'm struggling to find the right syntax for it.

like image 868
Hugh Avatar asked Feb 05 '23 17:02

Hugh


2 Answers

Partial template specialization is not allowed for function templates (it only works with class templates). You could use function template overloading instead:

template<typename S>
inline Vec2<S> add(const Vec2<S>& a, const Vec2<S>& b)
{
    return Vec2<S>(a.x + b.x, a.y + b.y);
}

It'll be selected when you call add with all the instantiations of Vec2 as arguments.


It would be better to change the parameters to pass-by-const-reference to avoid copy.

like image 166
songyuanyao Avatar answered Feb 08 '23 16:02

songyuanyao


You can't partially specialize function templates. But you can do it for class templates, so all your function needs to do is forward to one:

template<typename> struct add_impl;

template<typename T>
T add(const T a, const T b)
{
    return add_impl<T>::do_it(a, b);
}

template<typename T>
struct add_impl {
  static T do_it(const T a, const T b) { return a + b; }
};

template<typename S>
struct add_impl<Vec2<S> > {
  static Vec2<S> do_it(const Vec2<S> a, const Vec2<S> b) { 
    return Vec2<S>(a.x + b.x, a.y + b.y);
  }
};
like image 28
StoryTeller - Unslander Monica Avatar answered Feb 08 '23 15:02

StoryTeller - Unslander Monica