Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Template Function Specialisation C++ [duplicate]

I need to implement algorithm, that recursively calculates the scalar product of two vectors using templates.

There is my code:

#include <iostream>
#include <vector>

template<typename T, int Size>
T scalar_product(const std::vector<T> &a, const std::vector<T> &b)
{
    return a[Size - 1]*b[Size - 1] + (scalar_product<T, Size - 1>(a, b));
}

template<typename T>
T scalar_product<T, 0>(const std::vector<T> &a, const std::vector<T> &b) // error!
{
    return a[0] * b[0];
}

int main()
{
    std::vector<int> a(3, 1);
    std::vector<int> b(3, 3);

    std::cout << scalar_product<int, 3>(a, b);
    return 0;
}

If I use this specialisation T scalar_product<T, 0>(...), I get error "'scalar_product' : illegal use of explicit template arguments". But if I remove it like this T scalar_product(...) compiler report that recursion is going to be infinite (because there is no specialisation, as I understand).

There are a lot of questions of this type here, but I wasn't able to find useful answer. How can I specialize this function without using classes? Thank you beforehand!

like image 319
Ann Orlova Avatar asked Oct 21 '22 19:10

Ann Orlova


1 Answers

There is no partial function template specialization. You can either use a functor, which can be partially specialized:

template<typename T, int Size>
struct myFunctor
{
    T scalar_product(const std::vector<T> &a, const std::vector<T> &b)
    {
        static_assert(Size > 0,"Size must be positive!")
        return a[Size - 1]*b[Size - 1] + (myFunctor<typename T, Size - 1>::scalar_product(a, b));
    }
};
template<typename T>
struct myFunctor<T,1>
{
    T scalar_product(const std::vector<T> &a, const std::vector<T> &b)
    {
        return a[0] * b[0];
    }
};

Or you can achieve something like partial function specialization by using std::enable_if.

template<typename T, int Size>
typename std::enable_if<(Size>1), T>::type scalar_product(const std::vector<T> &a, const std::vector<T> &b)
{
    return a[Size - 1]*b[Size - 1] + (scalar_product<T, Size - 1>(a, b));
}
template<typename T, int Size>
T scalar_product(const std::vector<T> &a, const std::vector<T> &b, typename std::enable_if<(Size == 1), void*>::type x = nullptr)
{
    return a[0] * b[0];
}

Notice that I used 2 different ways to use std::enable_if in the 2 functions only to show that both are possible. Both functions can use enable_if on the return type like the first function does, and both of them could use them on an argument like the second function does. For additional reading see SFINAE.

Or as a third option you can handle the specialization inside the function like this:

template<typename T, int Size>
T scalar_product(const std::vector<T> &a, const std::vector<T> &b)
{
    static_assert(Size > 0,"Size must be positive!")
    if (Size==1)
        return a[0] * b[0];
    return a[Size - 1]*b[Size - 1] + (scalar_product<T, (Size==1) ? Size : Size - 1>(a, b));
}

Note that without (Size==0) ? Size : Size - 1, the compiler will create a function for all values of int, or die trying.

like image 168
Peter Avatar answered Nov 04 '22 18:11

Peter