El pupi
El pupi

Reputation: 458

C++ template class recursively required from

I am trying to code the Horner alogrithm using a meta programming code. Unfortunately the code doesn't compile. Here you find the compiler error:

In instantiation of ‘const int tuple_nth_element_v<1u, int, 1>::value’:
----> LINE 1 <---- recursively required from ‘const int tuple_nth_element_v<2u, int, 2, 1>::value’
required from ‘const int tuple_nth_element_v<3u, int, 1, 2, 1>::value’
----> LINE 2 <---- recursively required from ‘constexpr const double Horner_Impl<5, 2ul, int, 1, 2, 1>::value’
required from ‘constexpr const double Horner_Impl<5, 3ul, int, 1, 2, 1>::value’
required from ‘constexpr const double Horner<5, int, 1, 2, 1>::value’
required from here
incomplete type ‘tuple_nth_element_v<0u, int>’ used in nested name specifier

The code used the following:

template<unsigned int N, class T, T... t>
struct tuple_nth_element_v;

template <class T, T t0, T... t>
struct tuple_nth_element_v<0, T, t0, t...> {
    static const T value = t0;
};
template <unsigned int N, class T, T t0, T... t>
struct tuple_nth_element_v<N, T, t0, t...> {
---> LINE1 <----
    static const T value = tuple_nth_element_v<N-1, T, t...>::value;
};


template<int x, std::size_t i, class T, T... a>
struct Horner_Impl
{
----> LINE 2 <----
    constexpr static double value = Horner_Impl<x, i - 1, T, a...>::value * x + 
    tuple_nth_element_v<sizeof...(a) - i, T , a...>::value;
};

template<int x, class T, T... a>
struct Horner_Impl<x, 0, T, a...>
{
    constexpr static double value = tuple_nth_element_v<sizeof...(a), T , a...>::value;
};

template<int x, class T, T... a>
struct Horner
{
    constexpr static double value = Horner_Impl<x, sizeof...(a), T, a...>::value;
};

Someone would have an idea?

Upvotes: 1

Views: 2231

Answers (2)

Christopher Oicles
Christopher Oicles

Reputation: 3107

This way seems a little bit more straightforward to me because it takes one coefficient off the pack on each recursion instead of using a helper class to perform an indexed enumeration:

#include <iostream>

template <int x, typename T, T a_n, T ...a>
struct Horner {
    constexpr static double value = Horner<x, T, a...>::value * x + a_n;
};

template <int x, typename T, T a_n>
struct Horner<x, T, a_n> {
    constexpr static double value = a_n;
};

int main() {
    double y = Horner<3, int, 5, 3, 2, 8>::value;
    std::cout << y << "\n";
}

Upvotes: 3

Weak to Enuma Elish
Weak to Enuma Elish

Reputation: 4637

In tuple_nth_element_v, you recursively scroll through the parameter pack until N == 0, when N is the number of elements in the parameter pack. When N == 0, you can't have any elements in the parameter pack. The specialization for N == 0 requires at least one element in the parameter pack, and so it can't be selected. The only one that matches is the un-specialized class, which has no definition.

With Horner<2, int, 1, 2>, there is a series like this:

value = tuple_nth_element_v<2, int, 1, 2>::value = tuple_nth_element_v<1, int, 2>::value = tuple_nth_element_v<0, int>::value;

That last instantiation is the source of the error.

I'm not familiar with the algorithm, but I think your solution is to change

template <class T, T t0, T... t>
struct tuple_nth_element_v<0, T, t0, t...>

to

template <class T, T t0, T... t>
struct tuple_nth_element_v<1, T, t0, t...> //N is now 1, not 0

and in Horner_Impl, change

constexpr static double value = ... tuple_nth_element_v<sizeof...(a) - i, T , a...>::value;

to

constexpr static double value = ... tuple_nth_element_v<sizeof...(a) - i + 1, T , a...>::value; //note the + 1

Upvotes: 0

Related Questions