sham1810
sham1810

Reputation: 303

Variadic Template Recursion

I am trying to use recursion to solve this problem where if i call

decimal<0,0,1>();

i should get the decimal number (4 in this case).

I am trying to use recursion with variadic templates but cannot get it to work.

Here's my code;

template<>
int decimal(){
    return 0;
}



template<bool a,bool...pack>
int decimal(){
        cout<<a<<"called"<<endl;
        return a*2 + decimal<pack...>();
};

int main(int argc, char *argv[]){
    cout<<decimal<0,0,1>()<<endl;
    return 0;
}

What would be the best way to solve this?

Upvotes: 0

Views: 403

Answers (3)

Yakk - Adam Nevraumont
Yakk - Adam Nevraumont

Reputation: 275330

This is a C++14 solution. It is mostly C++11, except for std::integral_sequence nad std::index_sequence, both of which are relatively easy to implement in C++11.

template<bool...bs>
using bools = std::integer_sequence<bool, bs...>;

template<std::uint64_t x>
using uint64 = std::integral_constant< std::uint64_t, x >;

template<std::size_t N>
constexpr uint64< ((std::uint64_t)1) << (std::uint64_t)N > bit{};

template<std::uint64_t... xs>
struct or_bits : uint64<0> {};

template<std::int64_t x0, std::int64_t... xs>
struct or_bits<x0, xs...> : uint64<x0 | or_bits<xs...>{} > {};

template<bool...bs, std::size_t...Is>
constexpr
uint64<
  or_bits<
    uint64<
      bs?bit<Is>:std::uint64_t(0)
    >{}...
  >{}
>
from_binary( bools<bs...> bits, std::index_sequence<Is...> ) {
  (void)bits; // suppress warning
  return {};
}


template<bool...bs>
constexpr
auto from_binary( bools<bs...> bits={} )
-> decltype( from_binary( bits, std::make_index_sequence<sizeof...(bs)>{} ) )
{ return {}; }

It generates the resulting value as a type with a constexpr conversion to scalar. This is slightly more powerful than a constexpr function in its "compile-time-ness".

It assumes that the first bit is the most significant bit in the list.

You can use from_binary<1,0,1>() or from_binary( bools<1,0,1>{} ).

Live example.

This particular style of type-based programming results in code that does all of its work in its signature. The bodies consist of return {};.

Upvotes: 0

max66
max66

Reputation: 66200

A possible solution can be the use of a constexpr function (so you can use it's values it's value run-time, when appropriate) where the values are argument of the function.

Something like

#include <iostream>

constexpr int decimal ()
 { return 0; }

template <typename T, typename ... packT>
constexpr int decimal (T const & a, packT ... pack)
 { return a*2 + decimal(pack...); }

int main(int argc, char *argv[])
 {
   constexpr  int  val { decimal(0, 0, 1) };

   static_assert( val == 2, "!");

   std::cout << val << std::endl;

   return 0;
 }

But I obtain 2, not 4.

Are you sure that your code should return 4?

-- EDIT --

As pointed by aschepler, my example decimal() template function return "eturns twice the sum of its arguments, which is not" what do you want.

Well, with 0, 1, true and false you obtain the same; with other number, you obtain different results.

But you can modify decimal() as follows

template <typename ... packT>
constexpr int decimal (bool a, packT ... pack)
 { return a*2 + decimal(pack...); }

to avoid this problem.

Upvotes: 0

Aaron McDaid
Aaron McDaid

Reputation: 27133

template<typename = void>
int decimal(){
    return 0;
}

template<bool a,bool...pack>
int decimal(){
        cout<<a<<"called"<<endl;
        return a + 2*decimal<pack...>();
};

The problem was with the recursive case, where it expects to be able to call decltype<>(). That is what I have defined in the first overload above. You can essentially ignore the typename=void, the is just necessary to allow the first one to compile.

Upvotes: 3

Related Questions