Recently in a job interview I was asked to give the result of 100th element of a 3rd-class Fibonacci sequence(Fib(n)=Fib(n-1)+Fib(n-2)+Fib(n-3). I finished by Mathematical Induction and constructing a class to present numbers larger than long long. Then I was asked to implement it via template meta-programming. The problem is that the result will exceed the range of long long and I don't know how to fix this. Here is my code using template meta-programming.
template<long long num>
struct fib
{
enum { result = fib<num - 1>::result + fib<num - 2>::result + fib<num - 3>::result};
};
template<>
struct fib<0>
{
enum { result = 1 };
};
template<>
struct fib<1>
{
enum { result = 1 };
};
template<>
struct fib<2>
{
enum { result = 2 };
};
template<>
struct fib<3>
{
enum { result = 4 };
};
int main()
{
cout << fib<100>::result << endl;
return 0;
}
A possible implementation is to use a custom structure to store the numbers instead of a built-in type. You could for instance store numbers like this:
template <int... Digits>
struct number<Digits... > { };
Note: For the sake of simplicity when adding, I store the digits in reverse order, so the number 275 is stored as number<5, 7, 2>.
Fibonacci only requires addition, so you simply have to define addition, e.g., a template add (see the end of the answer for the actual implementation).
You can then define the fib template quite easily:
template <int N>
struct fib_impl {
using type = add_t<
typename fib_impl<N-1>::type,
typename fib_impl<N-2>::type,
typename fib_impl<N-3>::type>;
};
template <>
struct fib_impl<0> { using type = number<0>; };
template <>
struct fib_impl<1> { using type = number<0>; };
template <>
struct fib_impl<2> { using type = number<1>; };
template <int N>
using fib = typename fib_impl<N>::type;
And with an appropriate output operator (see below), you can print the 100th Tribonacci number:
int main() {
std::cout << fib<100>{} << "\n";
}
Which outputs:
53324762928098149064722658
While the 100th is not present in the OEIS, you can check that the 37th one is correct:
static_assert(std::is_same_v<fib<37>, number<2, 5, 8, 6, 3, 4, 2, 3, 1, 1>>);
Implementation of operator<<:
std::ostream& operator<<(std::ostream &out, number<>) {
return out;
}
template <int Digit, int... Digits>
std::ostream& operator<<(std::ostream &out, number<Digit, Digits... >) {
// Do not forget that number<> is in reverse order:
return out << number<Digits... >{} << Digit;
}
Implementation of the add template:
This is a small cat utility to concatenate numbers:
// Small concatenation utility:
template <class N1, class N2>
struct cat;
template <int... N1, int... N2>
struct cat<number<N1... >, number<N2... >> {
using type = number<N1... , N2...>;
};
template <class N1, class N2>
using cat_t = typename cat<N1, N2>::type;
The actual implementation of the addition:
template <class AccNumber, int Carry, class Number1, class Number2>
struct add_impl;
template <class AccNumber, int Carry>
struct add_impl<AccNumber, Carry, number<>, number<>> {
using type = std::conditional_t<Carry == 0, AccNumber, cat_t<AccNumber, number<1>>>;
};
template <class AccNumber, int Carry,
int Digit2, int... Digits2>
struct add_impl<AccNumber, Carry, number<>, number<Digit2, Digits2...>> {
using type = typename add_impl<
cat_t<AccNumber, number<(Digit2 + Carry) % 10>>,
(Digit2 + Carry) / 10,
number<Digits2... >, number<>>::type;
};
template <class AccNumber, int Carry,
int Digit1, int... Digits1>
struct add_impl<AccNumber, Carry, number<Digit1, Digits1... >, number<>> {
using type = typename add_impl<
cat_t<AccNumber, number<(Digit1 + Carry) % 10>>,
(Digit1 + Carry) / 10,
number<Digits1... >, number<>>::type;
};
template <class AccNumber, int Carry,
int Digit1, int... Digits1, int Digit2, int... Digits2>
struct add_impl<AccNumber, Carry, number<Digit1, Digits1... >, number<Digit2, Digits2...>> {
using type = typename add_impl<
cat_t<AccNumber, number<(Digit1 + Digit2 + Carry) % 10>>,
(Digit1 + Digit2 + Carry) / 10,
number<Digits1... >, number<Digits2... >>::type;
};
A short wrapper:
template <class... Numbers>
struct add;
template <class Number>
struct add<Number> {
using type = Number;
};
template <class Number, class... Numbers>
struct add<Number, Numbers... > {
using type = typename add_impl<
number<>, 0, Number, typename add<Numbers... >::type>::type;
};
template <class... Numbers>
using add_t = typename add<Numbers... >::type;
I am not aware of ready-to-use arbirtrary precicion facitlities for templates. However, a toy number-type that can hold numbers bigger than long long is easy to write:
template <long long H,long long L>
struct my_number {
static const long long high = H;
static const long long low = L;
static const long long mod = 10000000000;
static void print() {
std::cout << high << setw(10) << setfill('0') << low;
}
};
It stores the last 10 digits of the result in low and the leading digits in high. Two my_numbers can be summed via
template <typename A,typename B>
struct sum {
static const long long low = (A::low + B::low) % A::mod;
static const long long high = A::high + B::high + (A::low + B::low) / A::mod;
using number = my_number<high,low>;
};
and for 3 numbers:
template <typename A,typename B,typename C>
struct sum3 { using number = typename sum<A,sum<B,C>>::number; };
As already mentioned, this is just a toy example. Anyhow, once you have a number type that can represent big enough numbers you just have to adjust you fib with minor modifications:
template<long long num> struct fib {
using result_t = typename sum3< typename fib<num-1>::result_t,
typename fib<num-2>::result_t,
typename fib<num-3>::result_t
>::number;
};
template<> struct fib<0> { using result_t = my_number<0,1>; };
template<> struct fib<1> { using result_t = my_number<0,1>; };
template<> struct fib<2> { using result_t = my_number<0,2>; };
template<> struct fib<3> { using result_t = my_number<0,4>; };
int main() {
fib<100>::result_t::print();
}
I couldn't find a reliable source for the correct value of fib<100>, so unfortunately I couldn't test against that.
Full example is here.
You can accomplish this using Boost version 1.72 and boost::multiprecision:
#include <iostream>
#include <boost/multiprecision/cpp_int.hpp>
template <int x>
struct fib
{
static constexpr boost::multiprecision::uint1024_t value = x * fib<x - 1>::value;
};
template <>
struct fib<0>
{
static constexpr boost::multiprecision::uint1024_t value = 1;
};
int main()
{
std::cout << fib<100>::value;
}
Output:
93326215443944152681699238856266700490715968264381621468592963895217599993229915608941463976156518286253697920827223758251185210916864000000000000000000000000
This was run using Visual Studio 2019 and boost 1.72. Note that earlier versions of boost::multiprecision were not full constexpr, so this probably will not compile with earlier versions of boost.
EDIT:
Here is the third-class version. This is almost verbatim to the original poster's version, with the only difference being the usage of the constexpr-enabled big number class from boost:
#include <iostream>
#include <boost/multiprecision/cpp_int.hpp>
template<long long num>
struct fib
{
static constexpr boost::multiprecision::uint1024_t value = fib<num - 1>::value + fib<num - 2>::value + fib<num - 3>::value;
};
template<>
struct fib<0>
{
static constexpr boost::multiprecision::uint1024_t value = 1;
};
template<>
struct fib<1>
{
static constexpr boost::multiprecision::uint1024_t value = 1;
};
template<>
struct fib<2>
{
static constexpr boost::multiprecision::uint1024_t value = 2;
};
template<>
struct fib<3>
{
static constexpr boost::multiprecision::uint1024_t value = 4;
};
int main()
{
std::cout << fib<100>::value;
}
Output:
180396380815100901214157639
Related
I want to sum the number from 1 to N-1 by TMP. so I wrote a source code as shown below, but an error template argument '(number - 1)' involves template parameter(s) occurred. Do you happen to know how to deal with this?
template <int number, int i = 1>
class Sum {
public:
static const int result = i + Sum<number, i + 1>::result;
};
template <int number>
class Sum<number, number - 1> {
public:
static const int result = number - 1;
};
int main () {
const int result = Sum<10>::result;
return 0;
}
GCC still follows the rule:
Non-type argument expression cannot use the name of the template parameter except when it is exactly the name of the template parameter.
To solve the problem using template specialization, you can wrap the second non-type template parameter into an std::integral_constant to make it a type template parameter:
template<int number, class i = std::integral_constant<int, 1>>
struct Sum {
static constexpr int value = i() + Sum<number,
std::integral_constant<int, i() + 1>>::value;
};
template<int number>
struct Sum<number, std::integral_constant<int, number - 1>> {
static constexpr int value = number - 1;
};
static_assert(Sum<10>::value == 45);
Alternatively, you can use if constexpr and no partial specialization:
template<int number, int i = 1>
struct Sum {
static constexpr int value = [] {
if constexpr (number == i + 1)
return i;
else
return i + Sum<number, i + 1>::value;
}();
};
static_assert(Sum<10>::value == 45);
Yet another way is given by fold expressions:
template<class> struct Sum_impl;
template<int... numbers>
struct Sum_impl<std::integer_sequence<int, numbers...>> {
static constexpr int value = (... + numbers);
};
template<int number>
struct Sum : Sum_impl<std::make_integer_sequence<int, number>> {};
Suppose we have code like this. It works well and pre-calculate first 5 Fibonacci numbers.
#include <iostream>
template <int T>
struct fib;
template <>
struct fib<0>{
constexpr static int value = 1;
};
template <>
struct fib<1>{
constexpr static int value = 1;
};
template <int I>
struct fib{
constexpr static int value = fib<I - 1>::value + fib<I - 2>::value;
};
int main(){
std::cout << fib<0>::value << std::endl;
std::cout << fib<1>::value << std::endl;
std::cout << fib<2>::value << std::endl;
std::cout << fib<3>::value << std::endl;
std::cout << fib<4>::value << std::endl;
std::cout << fib<5>::value << std::endl;
}
However there is "small" problem with it.
What if we need to use this for values, that are not known at compile time?
For few values we can do this:
const int max = 5;
int getData(){
return 5; // return value between 0 and max.
}
int something(){
switch(getData()){
case 0: return fib<0>::value;
case 1: return fib<1>::value;
case 2: return fib<2>::value;
case 3: return fib<3>::value;
case 4: return fib<4>::value;
case 5: return fib<5>::value;
}
}
This will works OK for 5 values, but what if we have 150 or 300?
Is not really serious to change the code with 300 rows...
What could be the workaround here?
If you need to use a value at runtime that isn't known at compile time, you can't compute it at compile time. Obvious.
But... if you can impose a top value to values needed, you can compute all values (from zero to top) at compile time and store them in an std::array.
In the following example I have modified your fib structs (to use a std::size_t index and a template type (with default unsigned long) for the value) and I have added a templated struct fibVals that contain an std::array that is initialized using fib<n>::value
The following main() show that is possible to define a constexpr fibvals<N> (with N == 20 in the example) to compute (at compile time) all fib<n> values in range [0,N[.
#include <array>
#include <utility>
#include <iostream>
template <std::size_t, typename T = unsigned long>
struct fib;
template <typename T>
struct fib<0U, T>
{ constexpr static T value { T(1) }; };
template <typename T>
struct fib<1U, T>
{ constexpr static T value { T(1) }; };
template <std::size_t I, typename T>
struct fib
{ constexpr static T value { fib<I-1U>::value + fib<I-2U>::value }; };
template <std::size_t I, typename T = unsigned long>
struct fibVals
{
const std::array<T, I> vals;
template <std::size_t ... Is>
constexpr fibVals ( std::index_sequence<Is...> const & )
: vals { { fib<Is, T>::value ... } }
{ }
constexpr fibVals () : fibVals { std::make_index_sequence<I> { } }
{ }
};
int main()
{
constexpr fibVals<20> fv;
for ( auto ui = 0U ; ui < fv.vals.size() ; ++ui )
std::cout << "fib(" << ui << ") = " << fv.vals[ui] << std::endl;
}
Unfortunately this example use std::make_index_sequence<I> and std::index_sequence<Is...> that are C++14 features.
If you want implement struct fibVals in C++11, you can implement the following structs struct indexSeq and struct indexSeqHelper, to substitute std::index_sequence<Is...> and std::make_index_sequence<I>
template <std::size_t ...>
struct indexSeq
{ };
template <std::size_t N, std::size_t ... Next>
struct indexSeqHelper
{ using type = typename indexSeqHelper<N-1U, N-1U, Next ... >::type; };
template <std::size_t ... Next >
struct indexSeqHelper<0U, Next ... >
{ using type = indexSeq<Next ... >; };
and implement fibVals constructors as follows
template <std::size_t ... Is>
constexpr fibVals ( indexSeq<Is...> const & )
: vals { { fib<Is, T>::value ... } }
{ }
constexpr fibVals () : fibVals { typename indexSeqHelper<I>::type { } }
{ }
Templates are evaluated at compile time, so there is no solution with templates that works at runtime.
You can make a constexpr function, which may be evaluated at compile time, depending on the value passed. Obviously, a runtime value may not be computed at compile time, as it is not known at compile time.
Here's an issue I ran across while playing with variadic templates. I have some code that uses specialization to count "interesting" types in a parameter pack like so:
template<typename... _Pp>
struct count;
template<>
struct count<>
{
static const int value = 0;
};
// ignore uninteresting types
template<typename _First, typename... _Rest>
struct count<_First, _Rest...>
{
static const int value = count<_Rest...>::value;
};
// add 1 for a pointer
template<typename _First, typename... _Rest>
struct count<_First*, _Rest...>
{
static const int value = 1 + count<_Rest...>::value;
};
// add 1 for a reference
template<typename _First, typename... _Rest>
struct count<_First&, _Rest...>
{
static const int value = 1 + count<_Rest...>::value;
};
// add 1 for an int
template<typename... _Rest>
struct count<int, _Rest...>
{
static const int value = 1 + count<_Rest...>::value;
};
This code works fine, but I run into problems if I want to use the same approach to count class templates:
// add 1 for a vector
template<typename... _Rest>
struct count<vector, _Rest...>
{
static const int value = 1 + count<_Rest...>::value;
};
The above code fails to compile, error is "expected a type, got 'vector'" on the line beginning with "struct count". I'm also unable to something simpler, all class templates accepting a single argument:
// add 1 for a class template with 1 type parameter
template<template<typename> class _First, typename... _Rest>
struct count<_First, _Rest...>
{
static const int value = 1 + count<_Rest...>::value;
}
This code also fails to compile, complaining of "expected a type, got '_First'" once again on the line beginning with "struct count". Is someone familiar with a way to accomplish this goal using this approach (i.e. some modification that I can make to one or both of the specializations that will get them to compile and perform the desired calculation at compile time)?
EDIT:
I want the parameter pack for vector to be unbound, similar to the following code for a simple container wrapper with variadic template-template parameters that also specializes on std::vector:
// pass a container as a parameter using variadic template-template
parameter
template<typename _Tp, template<typename...> class _C>
struct success
{
// not specialized for any container
static const bool is_specialized = false;
// data member of container type
_C<_Tp> c_;
};
// partial specialization of above for std::vector
template<typename _Tp>
struct success<_Tp, std::vector>
{
// specialized for vector
static const bool is_specialized = true;
// again, data member of container type
std::vector<_Tp> c_;
};
EDIT
Seems like the final answer is that what I want to do can't be accomplished, but I have found a way to reframe the problem so that I cans solve it. Many thanks to those who helped.
If I understand correctly what you want... yes, you can create a templated struct that can count "class templates", so you can write something like
count<std::vector, std::map, std::set, std::pair>::value
but you can't mix class templates and simple typenames, so you can't write something like
count<std::vector, int &, float, std::set>::value
The problem is that if you define
template <typename... _Pp>
struct count;
you can pass std::vector<int> to it, because std::vector<int> is a typename, but you can't pass std::vector to it because std::vector isn't a typename; it's a template<typename...> class (or template template) that it's a total different things.
You can write something like the following struct countC
template <template<typename...> class ...>
struct countC;
template <>
struct countC<>
{ static const int value = 0; };
// ignore uninteresting templates
template<template<typename...> class F, template<typename...> class ... R>
struct countC<F, R...>
{ static const int value = countC<R...>::value; };
template <template<typename...> class ... R>
struct countC<std::vector, R...>
{ static const int value = 1 + countC<R...>::value; };
The following is a working complete example where I've rewritten your struct count as struct countT for count selected types, I've added a struct countC to count selected "class templates" and I've added a struct countV to count selected values of a fixed typename.
#include <map>
#include <set>
#include <vector>
#include <utility>
#include <iostream>
// countC for templates
template <template<typename...> class ...>
struct countC;
template <>
struct countC<>
{ static const int value = 0; };
// ignore uninteresting templates
template<template<typename...> class F, template<typename...> class ... R>
struct countC<F, R...>
{ static const int value = countC<R...>::value; };
template <template<typename...> class ... R>
struct countC<std::vector, R...>
{ static const int value = 1 + countC<R...>::value; };
template <template<typename...> class ... R>
struct countC<std::map, R...>
{ static const int value = 1 + countC<R...>::value; };
template <template<typename...> class ... R>
struct countC<std::pair, R...>
{ static const int value = 1 + countC<R...>::value; };
// countV for for values of a fixed type
template <typename T, T ... v>
struct countV;
template <typename T>
struct countV<T>
{ static const int value = 0; };
// ignore uninteresting values
template <typename T, T f, T ... r>
struct countV<T, f, r...>
{ static const int value = countV<T, r...>::value; };
// count only int odd values
template <int f, int ... r>
struct countV<int, f, r...>
{ static const int value = (f % 2) + countV<int, r...>::value; };
// countT for typenames
template <typename...>
struct countT;
template <>
struct countT<>
{ static const int value = 0; };
// ignore uninteresting types
template <typename F, typename ... R>
struct countT<F, R...>
{ static const int value = countT<R...>::value; };
template <typename F, typename ... R>
struct countT<F*, R...>
{ static const int value = 1 + countT<R...>::value; };
template<typename F, typename ... R>
struct countT<F&, R...>
{ static const int value = 1 + countT<R...>::value; };
template<typename ... R>
struct countT<int, R...>
{ static const int value = 1 + countT<R...>::value; };
int main()
{
std::cout << "countC vector + map + set + pair = "
<< countC<std::vector, std::map, std::set, std::pair>::value
<< std::endl;
std::cout << "countT int + float + bool* + double& + bool + int& = "
<< countT<int, float, bool*, double&, bool, int&>::value
<< std::endl;
std::cout << "countV int, 1 + 4 + 4 + 5 + 7 + 10 + 11 + 16 + 15 = "
<< countV<int, 1, 4, 4, 5, 7, 10, 11, 16, 15>::value
<< std::endl;
std::cout << "countV long, 1 + 4 + 4 + 5 + 7 + 10 + 11 + 16 + 15 = "
<< countV<long, 1, 4, 4, 5, 7, 10, 11, 16, 15>::value
<< std::endl;
return 0;
}
p.s.: sorry for my bad English.
How about something like this?
// add 1 for a vector
template<typename... _Rest, typename T>
struct count<vector<T>, _Rest...>
{
static const int value = 1 + count<_Rest...>::value;
};
And this?
// add 1 for a class template with 1 type parameter
template<template<typename> class _First, typename T, typename... _Rest>
struct count<_First<T>, _Rest...>
{
static const int value = 1 + count<_Rest...>::value;
};
It should be:
template<typename... _Rest, typename... T>
struct count<std::vector<T...>, _Rest...>
{
static const int value = 1 + count<_Rest...>::value;
};
Generic version:
template<template<typename...> class C, typename... _Rest, typename... T>
struct count<C<T...>, _Rest...>
{
static const int value = 1 + count<_Rest...>::value;
};
Variadic pack matters.
I'm now learning a little about templates and templates in C++11, C++14 and C++1z. I'm trying to write a variadic class template with an inside class that will associate an int to every template argument - and have a constexpr method that returns its array representation.
Let's say that I have ensured that the template cannot receive two of the same type as an argument. I was thinking about doing it somewhat like this:
template <typename... Types>
struct MyVariadicTemplate {
//we know that all types in Types... are different
template <int... Values>
struct MyInnerTemplate {
//I need to make sure that sizeof...(Values) == sizeof...(Types)
constexpr std::array<int, sizeof...(Values)> to_array() {
std::array<int, sizeof...(Values)> result = {Values...};
return result;
// this is only valid since C++14, as far as I know
}
};
};
this code should be valid (if it's not, I'd love to know why). Now, I'd like to add another inner template:
template <typedef Type>
struct AnotherInnerTemplate {};
that has a public typedef, which represents MyInnerTemplate with one on the position of Type in Types... and zeros elsewhere - and here I'm lost. I don't know how to proceed
I would appreciate any hint on how that can be done - and if I'm heading towards the wrong direction, I hope somebody can give me a hint on how to do that.
I think what you're looking for is something like this.
#include <array>
#include <cstddef>
#include <iostream>
#include <type_traits>
template <typename NeedleT, typename... HaystackTs>
constexpr auto get_type_index_mask() noexcept
{
constexpr auto N = sizeof...(HaystackTs);
return std::array<bool, N> {
(std::is_same<NeedleT, HaystackTs>::value)...
};
}
template <typename T, std::size_t N>
constexpr std::size_t ffs(const std::array<T, N>& array) noexcept
{
for (auto i = std::size_t {}; i < N; ++i)
{
if (array[i])
return i;
}
return N;
}
int
main()
{
const auto mask = get_type_index_mask<float, bool, int, float, double, char>();
for (const auto& bit : mask)
std::cout << bit;
std::cout << "\n";
std::cout << "float has index " << ffs(mask) << "\n";
}
Output:
00100
float has index 2
The magic happens in the parameter pack expansion
(std::is_same<NeedleT, HaystackTs>::value)...
where you test each type in HaystackTs against NeedleT. You might want to apply std::decay to either type if you want to consider, say, const int and int the same type.
template <int size, int... Values> struct AnotherImpl {
using Type = typename AnotherImpl<size - 1, Values..., 0>::Type;
};
template <int... Values> struct AnotherImpl<0, Values...> {
using Type = Inner<Values...>;
};
template <class T> struct Another {
using Type = typename AnotherImpl<sizeof...(Types) - 1, 1>::Type;
};
Full:
template <class... Types> struct My {
template <int... Values> struct Inner {
constexpr std::array<int, sizeof...(Values)> to_array() {
return std::array<int, sizeof...(Values)>{Values...};
}
};
template <int size, int... Values> struct AnotherImpl {
using Type = typename AnotherImpl<size - 1, Values..., 0>::Type;
};
template <int... Values> struct AnotherImpl<0, Values...> {
using Type = Inner<Values...>;
};
template <class T> struct Another {
using Type = typename AnotherImpl<sizeof...(Types) - 1, 1>::Type;
};
};
auto main() -> int {
My<int, float, char>::Another<int>::Type s;
auto a = s.to_array();
for (auto e : a) {
cout << e << " ";
}
cout << endl;
return 0;
}
prints:
1 0 0
Is this what you want?
I have a template class with some integers as arguments. One static const integer (call it Length) of this class needs to be calculated based on the arguments. The calculation does need a loop (as far as I know) so a simple expression won't help.
static int setLength()
{
int length = 1;
while (length <= someTemplateArgument)
{
length = length << 1;
}
return length;
}
The returned length should be used to init Length. Lengthis used as a fixed length of an array so I need it to be constant.
Is there a solution for this issue? I know that constexp could help but I can't use C11 or later.
Using metaprogramming. Implementation of C++11 enable_if taken from cppreference.com
#include <iostream>
template<bool B, class T = void>
struct enable_if {};
template<class T>
struct enable_if<true, T> { typedef T type; };
template <int length, int arg, typename = void>
struct length_impl
{
static const int value = length_impl<(length << 1), arg>::value;
};
template <int length, int arg>
struct length_impl<length, arg, typename enable_if<(length > arg)>::type>
{
static const int value = length ;
};
template <int arg>
struct length_holder
{
static const int value = length_impl<1, arg>::value;
};
template<int n>
struct constexpr_checker
{
static const int value = n;
};
int main()
{
std::cout << constexpr_checker< length_holder<20>::value >::value;
}