Related
I want to get a matrix from two parameter packs like the following:
template < typename T1, typename T2 > struct Multi{};
template < int ... n > struct N{};
void Print( int n ){ std::cout << n << std::endl; }
template < int ... n1, int ... n2 >
struct Multi< N<n1...>, N<n2...>>
{
Multi()
{
using expander = int[];
// No idea which syntax should be used here:
expander{ 0,((void)Print(n1...*n2),0)... };
}
};
int main()
{
Multi< N<1,2,3,4>, N< 10,20> >{};
}
The result should be
10 20 30 40 20 40 60 80
How can I do this?
No need to use the dummy arrays when you have fold expressions.
The naive (Print(n1 * n2), ...); wouldn't work (it expects the packs to have the same size, and would print N numbers instead of N2).
You need two nested fold expressions. In the inner one, you can prevent one of the packs from being expanded by passing it as a lambda parameter.
([](int n){(Print(n1 * n), ...);}(n2), ...);
This is not single expression, but you can expand it and use for loop
template < int ... n1, int ... n2 >
struct Multi< N<n1...>, N<n2...>>
{
Multi()
{
for(auto j : {n2...})
for(auto i : {n1...})
std::cout << i*j << '\n';
}
};
WandBox
I kind of assume that the output in your code is to check the compile time evaluation, since the output to std::cout only works at runtime.
Another option is not to use structs but to use constexpr functions,
they look more like regular c++ code. And you van validate the correctness at compile time using static_asserts. I did add some output at the end of my example
live demo here : https://onlinegdb.com/iNrqezstg
#include <array>
#include <iostream>
template<int... n>
constexpr auto array()
{
return std::array<int,sizeof...(n)>{n...};
};
template<std::size_t N, std::size_t M>
constexpr auto multiply(const std::array<int, N>& arr1, const std::array<int, M>& arr2)
{
std::array<int, N* M> result{};
std::size_t index{ 0 };
for (std::size_t n = 0; n < N; n++)
{
for (std::size_t m = 0; m < M; m++)
{
result[index] = arr1[n] * arr2[m];
++index;
}
}
return result;
}
template<typename container_t>
void show(const char* msg, const container_t& values)
{
std::cout << msg << " : ";
bool comma{ false };
for (const auto& value : values)
{
if (comma) std::cout << ", ";
std::cout << value;
comma = true;
}
std::cout << "\n";
}
int main()
{
constexpr auto arr1 = array<1, 2, 3, 4>();
constexpr auto arr2 = array<10, 20>();
constexpr auto result = multiply(arr1, arr2);
static_assert(arr1[0] == 1, "");
static_assert(arr2[1] == 20, "");
static_assert(result[0] == 10, "");
static_assert(result[1] == 20, "");
static_assert(result[6] == 40, "");
show("arr1", arr1);
show("arr2", arr2);
show("result", result);
return 0;
}
I'm trying to find the length of any given array and the methods I've tried so far won't work. This is my sizeOf function (not to be confused with sizeof):
template <typename T>
size_t sizeOf(T val) {
size_t sz = (size_t)0;
if (typeid(val).name()[0] == 'c') {
sz = (int)sizeof(val);
} else if (typeid(val).name()[1] == 'c' || typeid(val).name()[2] == 'c'){
sz = strlen((const char*)val);
} else if (typeid(val).name()[0] == 'i') {
sz = sizeof(val) / 4;
} else {
sz = 0; //new code here.
}
return sz;
}
So far, it works for strings, integers, and characters. The problem is finding the length of any array that isn't of type char. I tried using a for loop and subscripted values (e.g. arr[i]), but this exception occurs when the argument isn't an array: subscripted value is neither an array nor pointer. To this I try a try {...} catch () {...} statement and it still gives this error, so I can't use indices. I also tried another method with pointers: *(&arr + 1) - arr which works without errors, but the values are inconsistent or completely imprecise. Is there a way to acquire the true length of an array without the aforementioned methods and still have a flexible function?
Here's a solution that might work for you. It uses if constexpr to ensure that the first template only tries to compile valid branches in the code (you can add more if you need them) and a template overload to handle arrays of arbitrary type. Note: needs C++17 or later.
#include <iostream>
#include <cstring>
#include <type_traits>
template <typename T>
size_t sizeOf (T val)
{
size_t sz = 0;
if constexpr (std::is_integral_v <T>)
sz = sizeof (val);
else if constexpr (std::is_same_v <T, const char *>)
sz = strlen (val);
return sz;
}
template <typename T, size_t size>
size_t sizeOf (T (&)[size])
{
return size;
}
int main ()
{
int i = 0;
char c = 0;
std::cout << "sizeOf int = " << sizeOf (i) << "\n";
std::cout << "sizeOf char = " << sizeOf (c) << "\n";
const char *pc = "abcde";
std::cout << "sizeOf abcde = " << sizeOf (pc) << "\n";
int a [6];
std::cout << "sizeOf int [6] = " << sizeOf (a) << "\n";
}
Output:
sizeOf int = 4
sizeOf char = 1
sizeOf abcde = 5
sizeOf int [6] = 6
template <typename T>
size_t sizeOf(T const&) {
return 1;
}
template <typename T,nstd::size_t N>
size_t sizeOf(T const(&)[N]) {
return N;
}
template <typename T,nstd::size_t N>
size_t sizeOf(std::array<T,N> const&) {
return N;
}
template <typename T>
size_t sizeOf(T const* val) {
std::size_t N=0;
while (val&&val[0]){
++N;++val;
}
if(val)++N;// include null terminator, makes it comoatible with `"array"` length
return N
}
I'm coding in C++, and I have the following code:
int array[30];
array[9] = 1;
array[5] = 1;
array[14] = 1;
array[8] = 2;
array[15] = 2;
array[23] = 2;
array[12] = 2;
//...
Is there a way to initialize the array similar to the following?
int array[30];
array[9,5,14] = 1;
array[8,15,23,12] = 2;
//...
Note: In the actual code, there can be up to 30 slots that need to be set to one value.
This function will help make it less painful.
void initialize(int * arr, std::initializer_list<std::size_t> list, int value) {
for (auto i : list) {
arr[i] = value;
}
}
Call it like this.
initialize(array,{9,5,14},2);
A variant of aaronman's answer:
template <typename T>
void initialize(T array[], const T& value)
{
}
template <size_t index, size_t... indices, typename T>
void initialize(T array[], const T& value)
{
array[index] = value;
initialize<indices...>(array, value);
}
int main()
{
int array[10];
initialize<0,3,6>(array, 99);
std::cout << array[0] << " " << array[3] << " " << array[6] << std::endl;
}
Example: Click here
Just for the fun of it I created a somewhat different approach which needs a bit of infrastructure allowing initialization like so:
double array[40] = {};
"9 5 14"_idx(array) = 1;
"8 15 23 12"_idx(array) = 2;
If the digits need to be separated by commas, there is a small change needed. In any case, here is the complete code:
#include <algorithm>
#include <iostream>
#include <sstream>
#include <iterator>
template <int Size, typename T = int>
class assign
{
int d_indices[Size];
int* d_end;
T* d_array;
void operator=(assign const&) = delete;
public:
assign(char const* base, std::size_t n)
: d_end(std::copy(std::istream_iterator<int>(
std::istringstream(std::string(base, n)) >> std::skipws),
std::istream_iterator<int>(), this->d_indices))
, d_array()
{
}
assign(assign<Size>* as, T* a)
: d_end(std::copy(as->begin(), as->end(), this->d_indices))
, d_array(a) {
}
assign(assign const& o)
: d_end(std::copy(o.begin(), o.end(), this->d_indices))
, d_array(o.d_array)
{
}
int const* begin() const { return this->d_indices; }
int const* end() const { return this->d_end; }
template <typename A>
assign<Size, A> operator()(A* array) {
return assign<Size, A>(this, array);
}
void operator=(T const& value) {
for (auto it(this->begin()), end(this->end()); it != end; ++it) {
d_array[*it] = value;
}
}
};
assign<30> operator""_idx(char const* base, std::size_t n)
{
return assign<30>(base, n);
}
int main()
{
double array[40] = {};
"1 3 5"_idx(array) = 17;
"4 18 7"_idx(array) = 19;
std::copy(std::begin(array), std::end(array),
std::ostream_iterator<double>(std::cout, " "));
std::cout << "\n";
}
I just had a play around for the sake of fun / experimentation (Note my concerns at the bottom of the answer):
It's used like this:
smartAssign(array)[0][8] = 1;
smartAssign(array)[1][4][2] = 2;
smartAssign(array)[3] = 3;
smartAssign(array)[5][9][6][7] = 4;
Source code:
#include <assert.h> //Needed to test variables
#include <iostream>
#include <cstddef>
template <class ArrayPtr, class Value>
class SmartAssign
{
ArrayPtr m_array;
public:
class Proxy
{
ArrayPtr m_array;
size_t m_index;
Proxy* m_prev;
Proxy(ArrayPtr array, size_t index)
: m_array(array)
, m_index(index)
, m_prev(nullptr)
{ }
Proxy(Proxy* prev, size_t index)
: m_array(prev->m_array)
, m_index(index)
, m_prev(prev)
{ }
void assign(Value value)
{
m_array[m_index] = value;
for (auto prev = m_prev; prev; prev = prev->m_prev) {
m_array[prev->m_index] = value;
}
}
public:
void operator=(Value value)
{
assign(value);
}
Proxy operator[](size_t index)
{
return Proxy{this, index};
}
friend class SmartAssign;
};
SmartAssign(ArrayPtr array)
: m_array(array)
{
}
Proxy operator[](size_t index)
{
return Proxy{m_array, index};
}
};
template <class T>
SmartAssign<T*, T> smartAssign(T* array)
{
return SmartAssign<T*, T>(array);
}
int main()
{
int array[10];
smartAssign(array)[0][8] = 1;
smartAssign(array)[1][4][2] = 2;
smartAssign(array)[3] = 3;
smartAssign(array)[5][9][6][7] = 4;
for (auto i : array) {
std::cout << i << "\n";
}
//Now to test the variables
assert(array[0] == 1 && array[8] == 1);
assert(array[1] == 2 && array[4] == 2 && array[2] == 2);
assert(array[3] == 3);
assert(array[5] == 4 && array[9] == 4 && array[6] == 4 && array[7] == 4);
}
Let me know what you think, I don't typically write much code like this, I'm sure someone will point out some problems somewhere ;)
I'm not a 100% certain of the lifetime of the proxy objects.
The best you can do if your indexes are unrelated is "chaining" the assignments:
array[9] = array[5] = array[14] = 1;
However if you have some way to compute your indexes in a deterministic way you could use a loop:
for (size_t i = 0; i < 3; ++i)
array[transform_into_index(i)] = 1;
This last example also obviously applies if you have some container where your indexes are stored. So you could well do something like this:
const std::vector<size_t> indexes = { 9, 5, 14 };
for (auto i: indexes)
array[i] = 1;
Compilers which still doesn't support variadic template argument and universal initialization list, it can be a pain to realize, that some of the posted solution will not work
As it seems, OP only intends to work with arrays of numbers, valarray with variable arguments can actually solve this problem quite easily.
#include <valarray>
#include <cstdarg>
#include <iostream>
#include <algorithm>
#include <iterator>
template <std::size_t size >
std::valarray<std::size_t> selection( ... )
{
va_list arguments;
std::valarray<std::size_t> sel(size);
//Skip the first element
va_start ( arguments, size );
va_arg ( arguments, int );
for(auto &elem : sel)
elem = va_arg ( arguments, int );
va_end ( arguments );
return sel;
}
int main ()
{
//Create an array of 30 integers
std::valarray<int> array(30);
//The first argument is the count of indexes
//followed by the indexes of the array to initialize
array[selection<3>(9,5,14)] = 1;
array[selection<4>(8,15,13, 12)] = 2;
std::copy(std::begin(array), std::end(array),
std::ostream_iterator<int>(std::cout, " "));
return 0;
}
I remember, for static initialization exist syntax like:
int array[30] = {
[9] = 1, [8] = 2
}
And so on. This works in gcc, about another compilers - I do not know.
Use overload operator << .
#include <iostream>
#include <iomanip>
#include <cmath>
// value and indexes wrapper
template< typename T, std::size_t ... Ints> struct _s{ T value; };
//deduced value type
template< std::size_t ... Ints, typename T>
constexpr inline _s<T, Ints... > _ ( T const& v )noexcept { return {v}; }
// stored array reference
template< typename T, std::size_t N>
struct _ref
{
using array_ref = T (&)[N];
array_ref ref;
};
//join _s and _ref with << operator.
template<
template< typename , std::size_t ... > class IC,
typename U, std::size_t N, std::size_t ... indexes
>
constexpr _ref<U,N> operator << (_ref<U,N> r, IC<U, indexes...> ic ) noexcept
{
using list = bool[];
return ( (void)list{ false, ( (void)(r.ref[indexes] = ic.value), false) ... }) , r ;
//return r;
}
//helper function, for creating _ref<T,N> from array.
template< typename T, std::size_t N>
constexpr inline _ref<T,N> _i(T (&array)[N] ) noexcept { return {array}; }
int main()
{
int a[15] = {0};
_i(a) << _<0,3,4,5>(7) << _<8,9, 14>( 6 ) ;
for(auto x : a)std::cout << x << " " ;
// 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14
//result: 7 0 0 7 7 7 0 0 6 6 0 0 0 0 6
double b[101]{0};
_i(b) << _<0,10,20,30,40,50,60,70,80,90>(3.14)
<< _<11,21,22,23,24,25>(2.71)
<< _<5,15,25,45,95>(1.414) ;
}
struct _i_t
{
int * array;
struct s
{
int* array;
std::initializer_list<int> l;
s const& operator = (int value) const noexcept
{
for(auto i : l )
array[i] = value;
return *this;
}
};
s operator []( std::initializer_list<int> i ) const noexcept
{
return s{array, i};
}
};
template< std::size_t N>
constexpr _i_t _i( int(&array)[N]) noexcept { return {array}; }
int main()
{
int a[15] = {0};
_i(a)[{1,3,5,7,9}] = 7;
for(auto x : a)std::cout << x << ' ';
}
Any fancy trickery you do will be unrolled by the compiler/assembler into exactly what you have. Are you doing this for readability reasons? If your array is already init, you can do:
array[8] = array[15] = array[23] = array[12] = 2;
But I stress my point above; it will be transformed into exactly what you have.
I'm trying to understand the code:
#include <iostream>
#include <stdexcept>
// constexpr functions use recursion rather than iteration
constexpr int factorial(int n)
{
return n <= 1 ? 1 : (n * factorial(n-1));
}
// literal class
class conststr {
const char * p;
std::size_t sz;
public:
template<std::size_t N>
constexpr conststr(const char(&a)[N]) : p(a), sz(N-1) {}
// constexpr functions signal errors by throwing exceptions from operator ?:
constexpr char operator[](std::size_t n) const {
return n < sz ? p[n] : throw std::out_of_range("");
}
constexpr std::size_t size() const { return sz; }
};
constexpr std::size_t countlower(conststr s, std::size_t n = 0,
std::size_t c = 0) {
return n == s.size() ? c :
s[n] >= 'a' && s[n] <= 'z' ? countlower(s, n+1, c+1) :
countlower(s, n+1, c);
}
// output function that requires a compile-time constant, for testing
template<int n> struct constN {
constN() { std::cout << n << '\n'; }
};
int main()
{
std::cout << "4! = " ;
constN<factorial(4)> out1; // computed at compile time
volatile int k = 8; // disallow optimization using volatile
std::cout << k << "! = " << factorial(k) << '\n'; // computed at run time
std::cout << "Number of lowercase letters in \"Hello, world!\" is ";
constN<countlower("Hello, world!")> out2; // implicitly converted to conststr
}
What is the parameter
const char(&a)[N]
? I don't understand it.. seems like a reference to an array.. and what's the point in passing it to a constexpr constructor?
The parameter const char(&a)[N] is a reference to an array.
The point of it is that it allows the compiler to deduce the length of the array. Without the reference, const char a[N] as parameter would be equivalent to const char* a which doesn't allow the template parameter N to be deduced.
This is (along with the template<std::size_t N> part), a way to get the size of a constant string, so you can do:
conststr hello("Hello, World!");
and later:
size_t s = hello.size();
Background
Consider the following:
template <unsigned N>
struct Fibonacci
{
enum
{
value = Fibonacci<N-1>::value + Fibonacci<N-2>::value
};
};
template <>
struct Fibonacci<1>
{
enum
{
value = 1
};
};
template <>
struct Fibonacci<0>
{
enum
{
value = 0
};
};
This is a common example and we can get the value of a Fibonacci number as a compile-time constant:
int main(void)
{
std::cout << "Fibonacci(15) = ";
std::cout << Fibonacci<15>::value;
std::cout << std::endl;
}
But you obviously cannot get the value at runtime:
int main(void)
{
std::srand(static_cast<unsigned>(std::time(0)));
// ensure the table exists up to a certain size
// (even though the rest of the code won't work)
static const unsigned fibbMax = 20;
Fibonacci<fibbMax>::value;
// get index into sequence
unsigned fibb = std::rand() % fibbMax;
std::cout << "Fibonacci(" << fibb << ") = ";
std::cout << Fibonacci<fibb>::value;
std::cout << std::endl;
}
Because fibb is not a compile-time constant.
Question
So my question is:
What is the best way to peek into this table at run-time? The most obvious solution (and "solution" should be taken lightly), is to have a large switch statement:
unsigned fibonacci(unsigned index)
{
switch (index)
{
case 0:
return Fibonacci<0>::value;
case 1:
return Fibonacci<1>::value;
case 2:
return Fibonacci<2>::value;
.
.
.
case 20:
return Fibonacci<20>::value;
default:
return fibonacci(index - 1) + fibonacci(index - 2);
}
}
int main(void)
{
std::srand(static_cast<unsigned>(std::time(0)));
static const unsigned fibbMax = 20;
// get index into sequence
unsigned fibb = std::rand() % fibbMax;
std::cout << "Fibonacci(" << fibb << ") = ";
std::cout << fibonacci(fibb);
std::cout << std::endl;
}
But now the size of the table is very hard coded and it wouldn't be easy to expand it to say, 40.
The only one I came up with that has a similiar method of query is this:
template <int TableSize = 40>
class FibonacciTable
{
public:
enum
{
max = TableSize
};
static unsigned get(unsigned index)
{
if (index == TableSize)
{
return Fibonacci<TableSize>::value;
}
else
{
// too far, pass downwards
return FibonacciTable<TableSize - 1>::get(index);
}
}
};
template <>
class FibonacciTable<0>
{
public:
enum
{
max = 0
};
static unsigned get(unsigned)
{
// doesn't matter, no where else to go.
// must be 0, or the original value was
// not in table
return 0;
}
};
int main(void)
{
std::srand(static_cast<unsigned>(std::time(0)));
// get index into sequence
unsigned fibb = std::rand() % FibonacciTable<>::max;
std::cout << "Fibonacci(" << fibb << ") = ";
std::cout << FibonacciTable<>::get(fibb);
std::cout << std::endl;
}
Which seems to work great. The only two problems I see are:
Potentially large call stack, since calculating Fibonacci<2> requires we go through TableMax all the way to 2, and:
If the value is outside of the table, it returns zero as opposed to calculating it.
So is there something I am missing? It seems there should be a better way to pick out these values at runtime.
A template metaprogramming version of a switch statement perhaps, that generates a switch statement up to a certain number?
Thanks in advance.
template <unsigned long N>
struct Fibonacci
{
enum
{
value = Fibonacci<N-1>::value + Fibonacci<N-2>::value
};
static void add_values(vector<unsigned long>& v)
{
Fibonacci<N-1>::add_values(v);
v.push_back(value);
}
};
template <>
struct Fibonacci<0>
{
enum
{
value = 0
};
static void add_values(vector<unsigned long>& v)
{
v.push_back(value);
}
};
template <>
struct Fibonacci<1>
{
enum
{
value = 1
};
static void add_values(vector<unsigned long>& v)
{
Fibonacci<0>::add_values(v);
v.push_back(value);
}
};
int main()
{
vector<unsigned long> fibonacci_seq;
Fibonacci<45>::add_values(fibonacci_seq);
for (int i = 0; i <= 45; ++i)
cout << "F" << i << " is " << fibonacci_seq[i] << '\n';
}
After much thought into the problem, I came up with this solution. Of course, you still have to add the values to a container at run-time, but (importantly) they are not computed at run-time.
As a side note, it's important not to define Fibonacci<1> above Fibonacci<0>, or your compiler will get very confused when it resolves the call to Fibonacci<0>::add_values, since Fibonacci<0>'s template specialization has not been specified.
Of course, TMP has its limitations: You need a precomputed maximum, and getting the values at run-time requires recursion (since templates are defined recursively).
I know this question is old, but it intrigued me and I had to have a go at doing without a dynamic container filled at runtime:
#ifndef _FIBONACCI_HPP
#define _FIBONACCI_HPP
template <unsigned long N>
struct Fibonacci
{
static const unsigned long long value = Fibonacci<N-1>::value + Fibonacci<N-2>::value;
static unsigned long long get_value(unsigned long n)
{
switch (n) {
case N:
return value;
default:
return n < N ? Fibonacci<N-1>::get_value(n)
: get_value(n-2) + get_value(n-1);
}
}
};
template <>
struct Fibonacci<0>
{
static const unsigned long long value = 0;
static unsigned long long get_value(unsigned long n)
{
return value;
}
};
template <>
struct Fibonacci<1>
{
static const unsigned long long value = 1;
static unsigned long get_value(unsigned long n)
{
if(n == N){
return value;
}else{
return 0; // For `Fibonacci<N>::get(0);`
}
}
};
#endif
This seems to work, and when compiled with optimizations (not sure if you were going to allow that), the call stack does not get to deep - there is normal runtime recursion on the stack of course for values (arguments) n > N, where N is the TableSize used in the template instantiation. However, once you go below the TableSize the generated code substitutes a constant computed at compile time, or at worst a value "computed" by dropping through a jump table (compiled in gcc with -c -g -Wa,-adhlns=main.s and checked the listing), the same as I reckon your explicit switch statement would result in.
When used like this:
int main()
{
std::cout << "F" << 39 << " is " << Fibonacci<40>::get_value(39) << '\n';
std::cout << "F" << 45 << " is " << Fibonacci<40>::get_value(45) << '\n';
}
There is no call to a computation at all in the first case (value computed at compile time), and in the second case the call stack depth is at worst:
fibtest.exe!Fibonacci<40>::get_value(unsigned long n=41) Line 18 + 0xe bytes C++
fibtest.exe!Fibonacci<40>::get_value(unsigned long n=42) Line 18 + 0x2c bytes C++
fibtest.exe!Fibonacci<40>::get_value(unsigned long n=43) Line 18 + 0x2c bytes C++
fibtest.exe!Fibonacci<40>::get_value(unsigned long n=45) Line 18 + 0xe bytes C++
fibtest.exe!main() Line 9 + 0x7 bytes C++
fibtest.exe!__tmainCRTStartup() Line 597 + 0x17 bytes C
I.e. it recurses until it finds a value in the "Table". (verified by stepping through Disassembly in the debugger line by line, also by replacing the test ints by a random number <= 45)
The recursive part could also be replaced by the linear iterative solution:
static unsigned long long get_value(unsigned long n)
{
switch (n) {
case N:
return value;
default:
if (n < N) {
return Fibonacci<N-1>::get_value(n);
} else {
// n > N
unsigned long long i = Fibonacci<N-1>::value, j = value, t;
for (unsigned long k = N; k < n; k++) {
t = i + j;
i = j;
j = t;
}
return j;
}
}
}
If you have C++ compiler which supports variadic templates (C++0x standard ) you can save fibonacii sequence in a tuple at the compile time. At runtime you can access any element from that tuple by indexing.
#include <tuple>
#include <iostream>
template<int N>
struct Fib
{
enum { value = Fib<N-1>::value + Fib<N-2>::value };
};
template<>
struct Fib<1>
{
enum { value = 1 };
};
template<>
struct Fib<0>
{
enum { value = 0 };
};
// ----------------------
template<int N, typename Tuple, typename ... Types>
struct make_fibtuple_impl;
template<int N, typename ... Types>
struct make_fibtuple_impl<N, std::tuple<Types...> >
{
typedef typename make_fibtuple_impl<N-1, std::tuple<Fib<N>, Types... > >::type type;
};
template<typename ... Types>
struct make_fibtuple_impl<0, std::tuple<Types...> >
{
typedef std::tuple<Fib<0>, Types... > type;
};
template<int N>
struct make_fibtuple : make_fibtuple_impl<N, std::tuple<> >
{};
int main()
{
auto tup = typename make_fibtuple<25>::type();
std::cout << std::get<20>(tup).value;
std::cout << std::endl;
return 0;
}
With C++11: you may create a std::array and a simple getter: https://ideone.com/F0b4D3
namespace detail
{
template <std::size_t N>
struct Fibo :
std::integral_constant<size_t, Fibo<N - 1>::value + Fibo<N - 2>::value>
{
static_assert(Fibo<N - 1>::value + Fibo<N - 2>::value >= Fibo<N - 1>::value,
"overflow");
};
template <> struct Fibo<0u> : std::integral_constant<size_t, 0u> {};
template <> struct Fibo<1u> : std::integral_constant<size_t, 1u> {};
template <std::size_t ... Is>
constexpr std::size_t fibo(std::size_t n, index_sequence<Is...>)
{
return const_cast<const std::array<std::size_t, sizeof...(Is)>&&>(
std::array<std::size_t, sizeof...(Is)>{{Fibo<Is>::value...}})[n];
}
template <std::size_t N>
constexpr std::size_t fibo(std::size_t n)
{
return n < N ?
fibo(n, make_index_sequence<N>()) :
throw std::runtime_error("out of bound");
}
} // namespace detail
constexpr std::size_t fibo(std::size_t n)
{
// 48u is the highest
return detail::fibo<48u>(n);
}
In C++14, you can simplify some function:
template <std::size_t ... Is>
constexpr std::size_t fibo(std::size_t n, index_sequence<Is...>)
{
constexpr std::array<std::size_t, sizeof...(Is)> fibos{{Fibo<Is>::value...}};
return fibos[n];
}
My idea is to recursively save the fibonacci sequence in the variadic templates then convert it into an array. All of this are done at compile-time.
For example with n = 5 we have:
F<5>::array
= F<4, 0>::array
= F<3, 0, 1>::array
= F<2, 0, 1, 1>::array
= F<1, 0, 1, 1, 2>::array
= F<0, 0, 1, 1, 2, 3>::array
= { 0, 1, 1, 2, 3 }
Then we can index the array at runtime.
My C++14 implementation:
#include <cstdint>
#include <array>
#include <iostream>
template<uint64_t n>
struct Helper { static constexpr uint64_t value = Helper<n - 1>::value + Helper<n - 2>::value; };
template<>
struct Helper<0> { static constexpr uint64_t value = 0; };
template<>
struct Helper<1> { static constexpr uint64_t value = 1; };
template<u_int64_t x>
class Fib {
private:
template<u_int64_t n, u_int64_t...rest>
struct Get {
static constexpr std::array<u_int64_t, n + sizeof...(rest)> value = Get<n - 1, rest..., Helper<sizeof...(rest)>::value>::value;
};
template<u_int64_t...rest>
struct Get<0, rest...> {
static constexpr std::array<u_int64_t, sizeof...(rest)> value{rest...};
};
public:
static constexpr std::array<u_int64_t, x> sequence = Get<x>::value;
};
template<u_int64_t x>
constexpr std::array<u_int64_t, x> Fib<x>::sequence;
int main() {
for (int i = 0; i < 45; i++) std::cout << "F" << i << " = " << Fib<45>::sequence[i] << std::endl;
}
One of the basic tennants of C (and for the most part C++) is that you don't pay for what you don't need.
The automatic generation of look-up tables is just not something that the compiler needs to do for you. Even if you need that functionality, not everyone else necessarly does.
If you want a lookup table, write a program to make one. Then use that data in your program.
Don't use a template metaprogram if you want values to be calculated at runtime, just use a regular program to calculate values.
You can generate the switch or a static array using preprocessor metaprogramming techniques.
It is a good decision if the complexity does not exceed the limitations of that approach, and you prefer not extending your toolchain with extra steps that generate code or data.