Search code examples
c++templatesc++14variable-templates

Recursive variable templates


I was trying to use variable templates the same way I use some other templates, for example: we already know how to calculate a Fibonacci number or the power of a number using metaprogramming with template objects wrapping a static value or a enum value.

So, the first thing I did was trying to specialize a template variable, and it works as expected:

template <std::size_t VALUE> std::size_t value       = VALUE;
template <>                  std::size_t value<666u> = 1u;

std::cout << value<0u> << '\n';   // "0" as expected
std::cout << value<1u> << '\n';   // "1" as expected
std::cout << value<2u> << '\n';   // "2" as expected
std::cout << value<666u> << '\n'; // "1" as expected!!

Knowing that variable template specialization is possible I've tried to do a variable template Fibonacci number:

template <std::size_t ITERATION>
std::size_t fibonacci = fibonacci<ITERATION - 1u> + fibonacci<ITERATION - 2u>;
template <> std::size_t fibonacci<1u> = 1u;
template <> std::size_t fibonacci<0u> = 0u;

int main()
{
    std::cout << fibonacci<5> << '\n'; // "8" expected;
    return 0;
}

The error i get from Wandbox is the following:

error: expected primary-expression before ';' token
template <std::size_t ITERATION> std::size_t fibonacci = fibonacci<ITERATION - 1u> + fibonacci<ITERATION - 2u>;
                                                                                                              ^

I don't know what I'm doing wrong nor understand the error. I'm guessing that the error could be releated with the fact that the variable template isnt yet defined while I'm already using it so I'm wondering if is it even possible to achieve my goal with variable templates.

Any hint?

Thanks a lot.


Solution

  • My guess is that compilers do not yet implement variable templates properly. For instance, clang 3.7.0 compiles your code but (with a small bug fix: fibonacci<0u> = 1u) outputs 0 instead of 8 for fibonacci<5>.

    However, if we do

    std::cout << fibonacci<0> << '\n'; // "1" expected;
    std::cout << fibonacci<1> << '\n'; // "1" expected;
    std::cout << fibonacci<2> << '\n'; // "2" expected;
    std::cout << fibonacci<3> << '\n'; // "3" expected;
    std::cout << fibonacci<4> << '\n'; // "5" expected;
    std::cout << fibonacci<5> << '\n'; // "8" expected;
    

    then we get the expected results. Weird!

    Update Since function templates are more mature than variable templates, the following is a workaround:

    template <std::size_t ITERATION>
    constexpr std::size_t get_fibonacci()
    {
        return get_fibonacci<ITERATION - 1u>() + get_fibonacci<ITERATION - 2u>();
    }
    
    template <>
    constexpr std::size_t get_fibonacci<0u>() {
        return 1u;
    }
    
    template <>
    constexpr std::size_t get_fibonacci<1u>() {
        return 1u;
    }
    
    template <std::size_t ITERATION>
    std::size_t fibonacci = get_fibonacci<ITERATION>();