Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Template specialization when parameter values are equal

I have a function of the form

template<int a, int b>
void f();

That I'd like to specialize when a == b. Pseudocode looks something like:

template<int a>
void f<a, a>(){ //something}

template<int a, int b>
void f<a, b>(){ //something different}

Is this possible without partial template specialization issues?

Edit: Thanks for the quick reply. The method is actually inside of a class, more like this:

<typename a> class A{ 
    template<int b, int c> f(); 
}; 

A inst; 
inst.f<1,1>(); 
inst.f<1,2>(); 
like image 334
Ben Jones Avatar asked May 31 '13 21:05

Ben Jones


1 Answers

You cannot partially specialize a function template, but you can partially specialize a class template.

This leaves room for the following trick, where the actual work is being done by static member functions of a primary function template and a specialized function template, to which your original f() function delegates its responsibility:

#include <iostream>

namespace detail
{
    template<int A, int B>
    struct helper
    {
        static void call() { std::cout << "f<A, B>()" << std::endl; }
    };

    template<int A>
    struct helper<A, A>
    {
        static void call() { std::cout << "f<A, A>()" << std::endl; }
    };
}

template<int a, int b>
void f()
{
    detail::helper<a, b>::call();
}

This is how you could use your f() function template:

int main()
{
    f<1, 2>();
    f<1, 1>();
}

Here is a live example.

EDIT:

If your function template is a member function, things get slightly more complicated, but the solution outlined above for turning function template partial specialization into class template partial specialization is still viable.

This is how you would go about it based on the example provided in the comments.

First, forward-declare the helper class template and grant its instantiations the right to access your class template A's private members (the role of the additional type parameter T will become clear in a moment):

namespace detail
{
    template<typename T, int A, int B>
    struct helper;
}

template <typename a>
class A
{
public:
    template<int b, int c>
    void f();
private:
    template<typename, int, int> friend struct detail::helper;
};

Then you would define the helper class template and its specialization as done before, but adding a function parameter to the call() functions of the type necessary to manipulate the class object on which the original member function f() has been invoked:

namespace detail
{
    template<typename T, int A, int B>
    struct helper
    {
        static void call(T* p) { std::cout << "f<A, B>()" << std::endl; }
    };

    template<typename T, int A>
    struct helper<T, A, A>
    {
        static void call(T* p) { std::cout << "f<A, A>()" << std::endl; }
    };
}

Then you could define the member function f() as shown below:

template<typename a>
template<int b, int c>
void A<a>::f()
{
    detail::helper<A<a>, b, c>::call(this);
}

And eventually use it this way:

int main()
{
    A<int> inst;
    inst.f<1,1>();
    inst.f<1,2>();
}

This is all put together in this live example.

like image 183
Andy Prowl Avatar answered Oct 20 '22 15:10

Andy Prowl