6

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!

Ann Orlova
  • 1,338
  • 15
  • 24
  • Not related to your question but you can have a base case in your main recursive function that checks if size == 1, do this, else that. – Abhishek Bansal Dec 10 '13 at 10:02
  • 6
    I guess you are using Visual Studio. GCC/Clang error message is clearer: "**function template partial specialization is not allowed**" – gx_ Dec 10 '13 at 10:04
  • 4
    Why function templates cannot be partially specialized: http://stackoverflow.com/questions/5101516/why-function-template-cannot-be-partially-specialized – Peter Dec 10 '13 at 10:07
  • 1
    Do you really need recursive? – billz Dec 10 '13 at 10:10
  • 1
    Btw your base case is wrong: it should be `` not ``, or `` should `return 0;` – gx_ Dec 10 '13 at 10:16
  • 1
    FYI, there is a standard library algorithm [`std::inner_product`](http://en.cppreference.com/w/cpp/algorithm/inner_product) that will perform this task. – Blastfurnace Dec 10 '13 at 11:08

1 Answers1

4

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.

Community
  • 1
  • 1
Peter
  • 5,608
  • 1
  • 24
  • 43