Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Recursive template function with multiple types

I'm trying to write function that counts scalar product for two vectors. Here is the code and it works.

    template <int N> 
    int scalar_product (std::vector<int>::iterator a, 
                        std::vector<int>::iterator b) {
        return (*a) * (*b) + scalar_product<N - 1>(a + 1, b + 1);
    }

    template <>
    int scalar_product<0>(std::vector<int>::iterator a,
                          std::vector<int>::iterator b) {
        return 0;
    }

But here is the problem - i want to replace this iterators with template type, so that signature of function will look smth like this

    template <typename Iterator ,int N> 
    int scalar_product (Iterator a, Iterator b) {
        return (*a) * (*b) + scalar_product<N - 1>(a + 1, b + 1);
    }

    template <typename Iterator>
    int scalar_product<0>(Iterator a,
                          Iterator b) {
        return 0;
    }

But this doesn't work - I get compile error C2768: illegal use of explicit template arguments. It seems silly, but I couldn't find out what should I change to avoid this error.

like image 917
htzfun Avatar asked Dec 09 '13 08:12

htzfun


2 Answers

Actually, you don't have to use types - I find them pretty cumbersome and their semantics are different. You can not partially specialise a function, but you can overload them and make them behave like specialisations by providing default parameters values:

#include <type_traits>

template <typename Iterator>
int scalar_product(Iterator a, Iterator b, std::integral_constant<int, 0> = std::integral_constant<int, 0>()  ) 
{
    return 0;
}

template <int N, typename Iterator> 
int scalar_product (Iterator a, Iterator b, std::integral_constant<int, N> = std::integral_constant<int, N>() ) 
{
    return (*a) * (*b) + scalar_product(a + 1, b + 1, std::integral_constant<int, N-1>() );
}

int foo()
{
    int a[] = { 1, 2, 3, 4 };
    int b[] = { 1, 1, 1, 1 };
    return scalar_product<4>(a, b); // returns 10
}
like image 187
gwiazdorrr Avatar answered Oct 30 '22 18:10

gwiazdorrr


(AFAIK) there is no support for partial specialization of function templates, to obtain this functionality, you need to do it slightly differently, something like:

template <int N>
struct scalar
{
  template <typename Iterator>
  static int product(Iterator a, Iterator b)
  { (*a) * (*b) + scalar<N - 1>::product(a + 1, b + 1); }
};

template <>
struct scalar<0>
{
  template <typename Iterator>
  static int product(Iterator a, Iterator b)
  { return 0; }
};
like image 24
Nim Avatar answered Oct 30 '22 17:10

Nim