C++ metaprogramming - compile time search tree - c++

UPDATE: sorry for confusing terms - I do not need a binary-tree, but segment-tree or interval-tree.
Imagine I have to statically initialize a search tree each time mine program is executed.
Tree t;
t.add(10, 'Apple');
t.add(20, 'Pear');
t.add(50, 'Orange');
...
t.add(300, 'Cucumber');
..
// then I use it.
int key = 15;
String s = t.lookup(key) // Returns 'Apple' ( as the key is between 10 and 20)
The keys and values in a tree are "static", hard-coded, but have to be maintained from time to time. Is there are metaprogramming trick how to organise key values into binary-search tree (or a skip list) during compile time?
For example the whole search tree is implemented directly in code .text and nothing is held in .data? I can also "predict" number of keys and provide order them.

I suspect you are making a mountain out of a molehill here,
and that it's because:-
You believe that to statically initialize something in C++ you
have to do it at compiletime.
Either you are not acquainted with the
concepts of upper and lower bounds or else you don't know that the
{upper|lower} bound of v in a [partially] ordered sequence S can be
determined by binary search of S, and that you can count on the Standard Library
to do it at least that efficiently.
I think you want to have a statically initialized data structure mapping
integer keys to string literals such that, at runtime, you
can query it with an integer n and very efficiently
retrieve the string literal s (if any), whose key is the largest
that is not larger than n - with the additional proviso, presumably,
that n is not larger than all keys.
If that is right, then the statically initialized data structure you need
is simply a statically initialized map M of integers to string literals.
Template meta-programming is not in the frame.
Because of the (presumed) proviso that that a query shall fail for n larger
than all keys, you will need to include a sentinel value in M with a key 1
larger than the largest you want to find.
Then, for runtime integer n, you query M for the upper bound of n.
The upper bound of n in M is the smallest key larger than n, if any.
If the returned iterator it is M.end() then you have no string for n.
Otherwise, if it == M.begin(), then every key is greater than n,
so again you have no string for n. Otherwise, there must exist a <key,value>
located by --it, and that keymust be the largest key that is not
larger than n. So your string for n is that value.
#include <map>
static const std::map<int,char const *> tab =
{
{ 2,"apple" },
{ 5,"pear" },
{ 9,"orange" },
{ 14,"banana" },
{ 20,"plum" },
{ 20 + 1,nullptr }
};
const char * lookup(int n)
{
auto it = tab.upper_bound(n);
return it == tab.begin() || it == tab.end() ? nullptr : (--it)->second;
}
Prepend that to this example:
#include <iostream>
using namespace std;
int main(void)
{
for (int i = 0; i <= 21; ++i) {
cout << i;
char const *out = lookup(i);
cout << " -> " << (!out ? "Not found" : out) << endl;
}
return 0;
}
and the output will be:
0 -> Not found
1 -> Not found
2 -> apple
3 -> apple
4 -> apple
5 -> pear
6 -> pear
7 -> pear
8 -> pear
9 -> orange
10 -> orange
11 -> orange
12 -> orange
13 -> orange
14 -> banana
15 -> banana
16 -> banana
17 -> banana
18 -> banana
19 -> banana
20 -> plum
21 -> Not found
Now tab in this program is a static data structure, but it is not
initialized at compiletime. It is initialized in the global static
initialization of your program, before main is called. Unless you
have a requirement to shave nanoseconds off your program startup, I
can't think why you would need the map to be initialized at compiletime.
If nevertheless you do require it to be initialized at compiletime,
it is just a little fiddlier than this. You will need the map to be
a constexpr
object, meaning the compiler can construct it at compiletime; and for
that it must be of a literal type;
and that means you cannot use std::map, because it is not a literal type.
Therefore you will have to use instead:
constexpr std::pair<int,char const *> tab[]
{
{ 2,"apple" },
{ 5,"pear" },
{ 9,"orange" },
{ 14,"banana" },
{ 20,"plum" },
{ 20 + 1,nullptr }
};
or similar, and implement lookup(n) in essentially the manner shown,
but invoking std::upper_bound upon tab. There you'll find the
slightly fiddlier bits, which I'll leave you for the exercise, if you
want it.

I finally created what I wanted to achieve. It's overcomplicated and it looks like compiler optimizers are much smarter then I thought.
// Log "function"
template <int N>
struct LOG
{
static const int value = LOG<N/2>::value + 1;
};
template<>
struct LOG<0>
{
static const int value = 0;
};
// pow "function"
template <int N>
struct POW
{
static const int value = POW<N-1>::value * 2;
};
template<>
struct POW<1>
{
static const int value = 2;
};
template<>
struct POW<0>
{
static const int value = 1;
};
// Pair <key, value> to be a payload in a type list
template<int k, char v>
struct Pair
{
static const int key = k;
static const int value = v;
};
// type list manipulator - access n-th element
template <size_t, class...> struct element;
template <class TT, class...TTs>
struct element<0, TT, TTs...>
{
typedef TT type;
};
template <size_t K, class TT, class...TTs>
struct element<K, TT, TTs...>
{
typedef typename element<K-1, TTs...>::type type;
};
template<class... Ts>
struct V;
// Binary split search algorithm (pure templatized)
template<class T, class... Ts>
struct V<T, Ts...> : private V<Ts...>
{
template<size_t N = sizeof...(Ts), size_t level = LOG<sizeof...(Ts)+1>::value>
struct impl
{
template<size_t IDX>
inline static char search_impl(size_t n)
{
using namespace std;
static const int depth = LOG<N>::value;
static const int layer = depth - level;
static const int key = element<IDX, T, Ts...>::type::key;
static const size_t left_idx = IDX - ( N / POW<layer + 2>::value + 1);
static const size_t right_idx =
IDX + ( N / POW<layer + 2>::value + 1) > sizeof...(Ts) ?
sizeof...(Ts) :
IDX + ( N / POW<layer + 2>::value + 1);
//std::cout << setfill('*') << setw(layer) << ' '
// << "Level:" << level << " of:" << depth << std::endl
// << std::setw(layer) << ' '
// << "IDX/val/layer/POW/level: "
// << " " << IDX
// << "/" << key
// << "/" << layer
// << "/" << POW<layer>::value
// << "/" << level
// << "/" << left_idx
// << "/" << right_idx
// << std::endl;
if ( n < key )
return V<T, Ts...>::impl<N, level-1>::template search_impl<left_idx>(n);
else
return V<T, Ts...>::impl<N, level-1>::template search_impl<right_idx>(n);
}
};
template<size_t N>
struct impl<N,1>
{
template<size_t IDX>
inline static char search_impl(size_t n)
{
static const int key = element<IDX, T, Ts...>::type::key;
static const char value1 = element<IDX-1, T, Ts...>::type::value;
static const char value2 = element<IDX, T, Ts...>::type::value;
if ( n < key )
{
//std::cout << " *" << value1 << ' ' << IDX << std::endl;
return value1;
} else {
//std::cout << " *" << value2 << ' ' << IDX << std::endl;
return value2;
}
}
};
static void print()
{
std::cout << typeid(T).name() << ' ' << T::key << ' ' << (char)T::value << std::endl;
V<Ts...>::print();
}
static char search(size_t n)
{
static const size_t level = LOG<sizeof...(Ts)+1>::value;
static const size_t N = sizeof...(Ts);
static const int height = LOG<N>::value;
static const size_t root_idx = N / 2 + 1;
static const int key = element<root_idx, T, Ts...>::type::key;
//std::cout << "Level:" << level << " of:" << height << std::endl
// << "IDX/val: "
// << " " << root_idx
// << "/" << input[root_idx]
// << std::endl;
static const size_t left_idx = root_idx - ( N / POW<2>::value + 1);
static const size_t right_idx = root_idx + ( N / POW<2>::value + 1);
if( n < key)
return V<T, Ts...>::impl<N, level-1>::template search_impl<left_idx>(n);
else
return V<T, Ts...>::impl<N, level-1>::template search_impl<right_idx>(n);
}
};
template<>
struct V<>
{
static void print()
{}
};
int main(int argc, char *argv[])
{
int i = std::stoi(argv[1]);
typedef V<
Pair< 0x1,'a'>,
Pair< 0x11,'b'>,
Pair< 0x21,'c'>,
Pair< 0x31,'d'>,
Pair< 0x41,'e'>,
Pair< 0x51,'f'>,
Pair< 0x61,'g'>,
Pair< 0x71,'h'>,
Pair< 0x81,'i'>,
Pair< 0x91,'j'>,
Pair<0x101,'k'>,
Pair<0x111,'l'>,
Pair<0x121,'m'>,
Pair<0x131,'n'>,
Pair<0x141,'o'>
> TV;
std::cout << (char)TV::search(i) << std::endl;
return 0;
};
So this is it. Mine goal was to "force" the compiler to put all the constants into the code. As nothing is kept in the data segment. The resulting code inlines all the search_impl<*> methods together and the result contains only "cmp" and "jae" instructions. But it looks like a reasonable compiler will do this anyway, if the array to be searched is defined as const static.

I would use a switch to do the lookup.
The compiler is free to use a jump table, binary search, or any other technique to optimize the lookup. For most switch tables, the compiler will generally emit the fastest possible thing.
switch (key)
{
case 10: return "Apple";
case 20: return "Pear";
...
}

Related

Finding duplicate values of std::map at compile time

I have a template class (BiMap) which is used as a bidirectional map for lookup purposes e.g. an enum value mapped to a std::string equivalent and vice versa.
To achieve this the std::string values must also be unique to prevent duplicate std::string values returning the first found enum key during a search by value lookup.
template<typename Key, typename Value>
class BiMap {
public:
explicit BiMap(std::initializer_list<std::pair<Key, Value>> &&items) : bimap_{items.begin(), items.end()} {
assert(!HasDuplicates(bimap_));
}
Key GetKeyFromValue(const Value &value) const {
auto it = std::find_if(bimap_.begin(), bimap_.end(), [&value](const std::pair<Key, Value> &kvp) {
return kvp.second == value;
});
return (it != bimap_.end() ? it->first : Key());
}
Value GetValueFromKey(const Key &key) const {
auto it = bimap_.find(key);
return (it != bimap_.end() ? it->second : Value());
}
private:
const std::map<Key, Value> bimap_;
};
I use a function called HasDuplicates to check for any duplicate values:
template<typename Key, typename Value>
bool HasDuplicates(const std::map<Key, Value> &bimap) {
// Create a map to use the values as keys
std::map<Value, Key> value_key_map;
for (auto &kvp : bimap) value_key_map.emplace(kvp.second, kvp.first);
// If there are no duplicate values then the sizes should be the same
std::cout << "HasDuplicates: " << std::boolalpha << (value_key_map.size() != bimap.size()) << std::endl;
return (value_key_map.size() != bimap.size());
}
And I can run the following example code which will indicate at runtime whether there is any duplicate values:
// Test 1: No duplicates
std::cout << "**No duplicates test:**" << std::endl;
const BiMap<std::string, int> bi_map_no_dups({{"foo", 1}, {"bar", 2}, {"foobar", 3}});
std::cout << "foo: " << bi_map_no_dups.GetValueFromKey("foo") << std::endl;
std::cout << "bar: " << bi_map_no_dups.GetValueFromKey("bar") << std::endl;
std::cout << "foobar: " << bi_map_no_dups.GetValueFromKey("foobar") << std::endl;
// Test 2: Duplicates
std::cout << "**Duplicates test:**" << std::endl;
const BiMap<std::string, int> bi_map_dups({{"foo", 1}, {"bar", 2}, {"foobar", 1}});
std::cout << "foo: " << bi_map_dups.GetValueFromKey("foo") << std::endl;
std::cout << "bar: " << bi_map_dups.GetValueFromKey("bar") << std::endl;
std::cout << "foobar: " << bi_map_dups.GetValueFromKey("foobar") << std::endl;
The output of this would be:
**No duplicates test:**
HasDuplicates: false
foo: 1
bar: 2
foobar: 3
**Duplicates test:**
HasDuplicates: true
main.cpp:22: BiMap<Key, Value>::BiMap(std::initializer_list<std::pair<_T1, _T2> >&&) [with Key = std::basic_string<char>; Value = int]: Assertion `!HasDuplicates(bimap_)' failed.
A working example of the above code can be found here.
The Question:
How can I evaluate whether the std::map has duplicate values at compile time?
What I've tried:
I've already tried to implement the constexpr template function like here:
template <typename K, typename V> constexpr bool has_duplicates(const std::map<K,V> *map)
{
std::map<V,K> value_key_map;
for(auto &kvp : map) value_key_map.emplace(map->second,map->first);
return map->size() == value_key_map.size();
}
int main() {
// Cannot get this part to work
constexpr std::map<std::string, int> bimap({{"foo", 1}, {"bar", 2}, {"foobar", 1}});
static_assert(!has_duplicates(&bimap));
return 0;
}
Note: I'm using C++11 where I cannot yet declare local variables and loops inside the constexpr function and should thus revert to recursion as seen here. But, for this example I'm happy if I can find a suitable solution with C++14's constexpr features and I'll get a recursive version later on (if possible).
How can I evaluate whether the std::map has duplicate values at compile time?
You can't. std::map() isn't usable at compile time.
You could instead use https://github.com/serge-sans-paille/frozen or https://github.com/mapbox/eternal to make that check (or some other constexpr structure).
The other way (if you want to stay at the C++11 level) is to build a template metaprogramming based map, like in this answer.
With the help of the comment section, I was able to formulate a suitable solution to my problem.
Important: std::map is not constexpr and can't be used to evaluate its contents at compile time.
However, you can use std::array<std::pair<const K, V>, N> to assist in evaluating the contents at compile time from C++14 as follows:
template<typename K, typename T, size_t N>
constexpr bool has_duplicates(const std::array<std::pair<K, T>, N> *arr) {
for (int i = 0; i < N - 1; i++) {
for (int j = i + 1; j < N; j++) {
if (compare_equal((*arr)[i].second,(*arr)[j].second) ||
compare_equal((*arr)[i].first, (*arr)[j].first)) return true;
}
}
return false;
}
with usage:
constexpr std::array<std::pair<int, const char *>, 3> arrd{{ {1, "foobar"},
{2, "bar"},
{3, "foobar"}}};
static_assert(!has_duplicates(&arrd), "Duplicates Found!");
and you need the following additional comparison functions:
template<typename A, typename B>
constexpr bool compare_equal(A a, B b) {
return a == b;
}
template <>
constexpr bool compare_equal(const char * a, const char * b) {
return *a == *b && (*a == '\0' || compare_equal(a + 1, b + 1));
}
For C++11 support you need to change the has_duplicates function to a recursive implementation. Here is a fully working example of both versions.
You can thus use this in your class to check for duplicate values at compile time.

Generating floating point limits at compile time via template arguments and constexpr semantics:

I'm working on a set of classes. My Function class will take a Functor class which stores a function pointer to some defined function which has an operator that will invoke the function call from the function pointer. It uses a Limit class that currently takes <int,int> for its upper and lower bounds. It has nothing but static constexpr functions to return the bounds and to calculate the number of elements between those bounds. If the lower bounds = 1 and upper bounds = 5 it will generate 5 for the number of elements to be evaluated for that function...
Here is what I'm doing with these classes:
First I declare a function such as f(x) = x, f(x) = x^2, or f(x) = cos(x), etc.
Then I instantiate a Functor object based on the above function(s) parameter types both for the return and for its parameter-argument types...
Next, I assign the function to my Functor class's member variable.
Then I instantiate a Function object giving it the data-type and the Lower & Upper limits for the range of the function.
The Function class upon construction automatically generates the data points of that function from [lower,upper] and stores the generated values in its internal array.
The Function class also contains an operator that will allow the user to get any value from any given input.
Pseudo Example:
f(x) = x^2;
Functor<T,T> functor;
functor.member = &f(x);
Function<T,Lower,Upper,T> function(functor);
// If T=int, Lower = -4, and Upper = 4 then the internal data set will be
// (-4,16) (-3,9), (-2,4), (-1,1), (0,0), (1,1), (2,4), (3,9), (4,16)
// The user can also use it's operator to call function(9) and it will return 81
Here is my working program that is generating datasets of values from my classes using various functions:
main.cpp
#include <cmath>
#include <exception>
#include <iostream>
#include "Function.h"
int main() {
try {
pipes::Functor<int, int> functor1;
functor1.FuncPtr = &square;
pipes::Function<int, -10, 10, int> func1( functor1 );
auto data1{ func1.data() };
for (auto& p : data1)
std::cout << '(' << p.first << ',' << p.second << ")\n";
std::cout << '\n';
std::cout << "f(25) = " << func1(25) << "\n\n";
pipes::Functor<int, int> functor2;
functor2.FuncPtr = &linear;
pipes::Function<int, -10, 10, int> func2(functor2);
auto data2{ func2.data() };
for (auto& p : data2)
std::cout << '(' << p.first << ',' << p.second << ")\n";
std::cout << '\n';
std::cout << "f(25) = " << func2(25) << "\n\n";
pipes::Functor<double, double> functor3;
functor3.FuncPtr = &cosine;
pipes::Function<double, -7, 7, double> func3(functor3);
auto data3{ func3.data() };
for (auto& p : data3)
std::cout << '(' << p.first << ',' << p.second << ")\n";
std::cout << '\n';
std::cout << "f(25) = " << func3(25) << "\n\n";
}
catch (const std::exception& e) {
std::cerr << e.what() << "\n\n";
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
Function.h
#pragma once
#include <array>
namespace pipes {
template<typename Ret, typename... Args>
struct Functor {
Ret(*FuncPtr)(Args...);
Ret operator()(Args... args) { return FuncPtr(args...); }
};
template<int Lower, int Upper>
class Limits {
public:
static constexpr unsigned lower_bound() { return Lower; }
static constexpr unsigned upper_bound() { return Upper; }
static constexpr unsigned element_count() { return (Upper - Lower + 1); }
};
template<typename T, int Lower, int Upper, typename... Args>
class Function {
std::array<std::pair<T, T>, Limits<Lower,Upper>::element_count()> data_points_;
Functor<T,Args...> functor_;
public:
Function(Functor<T,Args...> func) {
functor_ = func;
for (unsigned i = 0; i < Limits<Lower,Upper>::element_count(); i++) {
data_points_[i].first = ((T)i + (T)Lower);
data_points_[i].second = functor_(data_points_[i].first);
}
}
T operator()(Args... args) const {
return functor_.FuncPtr(args...);
}
constexpr auto lower() const { return Lower; }
constexpr auto upper() const { return Upper; }
constexpr auto count() const { return Limits<Lower,Upper>::element_count(); }
constexpr auto data() const { return data_points_; }
};
} // namespace pipes
When I run the program it is generating this output which appears to be correct:
Output
(-10,100)
(-9,81)
(-8,64)
(-7,49)
(-6,36)
(-5,25)
(-4,16)
(-3,9)
(-2,4)
(-1,1)
(0,0)
(1,1)
(2,4)
(3,9)
(4,16)
(5,25)
(6,36)
(7,49)
(8,64)
(9,81)
(10,100)
f(25) = 625
(-10,-10)
(-9,-9)
(-8,-8)
(-7,-7)
(-6,-6)
(-5,-5)
(-4,-4)
(-3,-3)
(-2,-2)
(-1,-1)
(0,0)
(1,1)
(2,2)
(3,3)
(4,4)
(5,5)
(6,6)
(7,7)
(8,8)
(9,9)
(10,10)
f(25) = 25
(-7,0.753902)
(-6,0.96017)
(-5,0.283662)
(-4,-0.653644)
(-3,-0.989992)
(-2,-0.416147)
(-1,0.540302)
(0,1)
(1,0.540302)
(2,-0.416147)
(3,-0.989992)
(4,-0.653644)
(5,0.283662)
(6,0.96017)
(7,0.753902)
f(25) = 0.991203
And now for my question where this becomes the tricky part...
With my code currently the way it is, everything is fine as long as my bounds [-a,b] are of an integral type...
Let's suppose on my last example such as with cos, what if I want to have my bounds from [-2pi,2pi] where the lower and upper limits are of floating-point types...
The Issue:
Currently in C++ this is non-standard and in most cases won't compile:
template<float val> // or template<double>
struct foo() {
constexpr float operator()() {
return val;
}
};
And the above prevents me from doing something like this:
constexpr double PI{ 6.28318531 };
pipes::Functor<double, double> functor3;
functor3.FuncPtr = &cosine;
pipes::Function<double, -PI, PI, double> func3(functor3);
auto data3{ func3.data() };
for (auto& p : data3)
std::cout << '(' << p.first << ',' << p.second << ")\n";
std::cout << '\n';
std::cout << "f(25) = " << func3(25) << "\n\n";
So if I want to be able to support floating-point types for my intervals of my Limits or Range class... What kind of alternative would there be if such a thing is currently possible in c++? Or would I just have to simply restructure the way my class templates are designed?
If the above is possible in some way during compile time via templates and constexpr semantics, then there is another issue that arises that will have to be taken into consideration and that would be the stepping interval for use with floating-point types to know how many data points there will be within the dataset... (basically calculating dx based on some stepping value which would be defined by the user, for example: (0.1, 0.001, etc...) and the number of data points would be calculated by the number of these divisions between [lower, upper]... However, if the stepping value is known at compile-time, then calculating the divisions should be simple enough... that's not a major concern. The bigger concern is being able to express floating-point constants at compile time for template evaluation...
Currently, with the way my code is with its design, I have hit a limit on its functionality... I'm not sure how to provide a similar interface to support a floating-point range that can be calculated and generated at compile time! Any bit of help or suggestions is welcomed!
I think the closest you can get to a construct like yours is:
#include <iostream>
#include <array>
constexpr const double PI_2{ 6.28318531 };
template<double const &lower, double const &upper>
void foo() {
static_assert(lower<upper, "invalid lower and upper value");
constexpr size_t size = (upper-lower);
std::array<int, size> test;
std::cout << lower << " " << upper << " " << test.size() << std::endl;
}
template<double const &V>
struct neg {
static constexpr double value = -V;
};
int main()
{
foo<neg<PI_2>::value, PI_2>();
return 0;
}
If you can always specify the type as first template argument you could have something like this:
template<typename T, T const &lower, T const &upper>
void foo() {
std::cout << lower << " " << upper << std::endl;
}
I didn't fully think it through, how to get the floating-point part and the other together, but I think it should be possible.
In modern C++ and how templates are currently designed, I had to slightly restructure my code. It's forcing me to have to use std::vector instead of std::array, because we can't use floating-point types as constant template arguments... So I ended up having to change two of my classes... I had to change my Limits class, and my Function class.
My Limits class now accepts a Type instead of constant-integral-type and it stores 3 member variables. It also has a default constructor and a user constructor. The functions are now just constexpr instead of being static.
My Function class now stores a Limits class object and data_points_ is no longer an std::array as it is now std::vector. It's constructor now also takes in a Limits object.
I had also taken into account for the step size for floating-point ranges.
Here is what my modified code looks like with its given output:
main.cpp
#include <cmath>
#include <iostream>
#include <exception>
#include "Function.h"
constexpr int square(int x) {
return x * x;
}
constexpr int linear(int x) {
return x;
}
double cosine(double x) {
return cos(x);
}
//template<float val>
struct foo {
float operator()(float val) { return val; }
};
int main() {
try {
pipes::Functor<int, int> functor1;
pipes::Limits<int> limit1(-10, 10, 1);
functor1.FuncPtr = &square;
pipes::Function<int, int, int> func1( limit1, functor1 );
auto data1{ func1.data() };
for (auto& p : data1)
std::cout << '(' << p.first << ',' << p.second << ")\n";
std::cout << '\n';
std::cout << "f(25) = " << func1(25) << "\n\n";
pipes::Functor<int,int> functor2;
pipes::Limits<int> limit2(-10, 10, 1);
functor2.FuncPtr = &linear;
pipes::Function<int, int, int> func2(limit2, functor2);
auto data2{ func2.data() };
for (auto& p : data2)
std::cout << '(' << p.first << ',' << p.second << ")\n";
std::cout << '\n';
std::cout << "f(25) = " << func2(25) << "\n\n";
constexpr double PI{ 6.28318531 };
pipes::Functor<double, double> functor3;
pipes::Limits<double> limits3( (-PI), PI, 0.1);
functor3.FuncPtr = &cosine;
pipes::Function<double, double, double> func3(limits3, functor3);
auto data3{ func3.data() };
for (auto& p : data3)
std::cout << '(' << p.first << ',' << p.second << ")\n";
std::cout << '\n';
std::cout << "f(25) = " << func3(25) << "\n\n";
}
catch (const std::exception& e) {
std::cerr << e.what() << "\n\n";
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
Function.h
#pragma once
#include <vector>
namespace pipes {
template<typename Ret, typename... Args>
struct Functor {
Ret(*FuncPtr)(Args...);
Ret operator()(Args... args) { return FuncPtr(args...); }
};
template<typename Ty>
class Limits {
private:
Ty Lower;
Ty Upper;
Ty Step;
public:
Limits() {}
Limits(Ty lower, Ty upper, Ty step) : Lower{ lower }, Upper{ upper }, Step{ step } {}
constexpr Ty lower_bound() { return Lower; }
constexpr Ty upper_bound() { return Upper; }
constexpr Ty step_size() { return Step; }
constexpr unsigned element_count() { return (unsigned)((Upper - Lower + 1)/Step); }
};
template<typename LimT, typename FuncT, typename... Args>
class Function {
Limits<LimT> limits_;
Functor<FuncT, Args...> functor_;
std::vector<std::pair<FuncT, FuncT>> data_points_;
public:
Function(Limits<LimT> limits, Functor<FuncT,Args...> func) {
limits_ = limits;
functor_ = func;
data_points_.resize( limits_.element_count() );
for (unsigned i = 0; i < limits_.element_count(); i++) {
auto x = limits_.lower_bound() + (i * limits_.step_size());
data_points_[i].first = (x);
data_points_[i].second = functor_(x);
}
}
FuncT operator()(Args... args) const {
return functor_.FuncPtr(args...);
}
constexpr auto lower() const { return limits_.lower_bound(); }
constexpr auto upper() const { return limits_.upper_bound(); }
constexpr auto count() const { return limits_.element_count(); }
constexpr auto step() const { return limits_.step_size(); }
constexpr auto data() const { return data_points_; }
};
} // namespace pipes
Output
(-10,100)
(-9,81)
(-8,64)
(-7,49)
(-6,36)
(-5,25)
(-4,16)
(-3,9)
(-2,4)
(-1,1)
(0,0)
(1,1)
(2,4)
(3,9)
(4,16)
(5,25)
(6,36)
(7,49)
(8,64)
(9,81)
(10,100)
f(25) = 625
(-10,-10)
(-9,-9)
(-8,-8)
(-7,-7)
(-6,-6)
(-5,-5)
(-4,-4)
(-3,-3)
(-2,-2)
(-1,-1)
(0,0)
(1,1)
(2,2)
(3,3)
(4,4)
(5,5)
(6,6)
(7,7)
(8,8)
(9,9)
(10,10)
f(25) = 25
(-6.28319,1)
(-6.18319,0.995004)
(-6.08319,0.980067)
(-5.98319,0.955336)
(-5.88319,0.921061)
(-5.78319,0.877583)
(-5.68319,0.825336)
(-5.58319,0.764842)
(-5.48319,0.696707)
(-5.38319,0.62161)
(-5.28319,0.540302)
(-5.18319,0.453596)
(-5.08319,0.362358)
(-4.98319,0.267499)
(-4.88319,0.169967)
(-4.78319,0.0707372)
(-4.68319,-0.0291995)
(-4.58319,-0.128844)
(-4.48319,-0.227202)
(-4.38319,-0.32329)
(-4.28319,-0.416147)
(-4.18319,-0.504846)
(-4.08319,-0.588501)
(-3.98319,-0.666276)
(-3.88319,-0.737394)
(-3.78319,-0.801144)
(-3.68319,-0.856889)
(-3.58319,-0.904072)
(-3.48319,-0.942222)
(-3.38319,-0.970958)
(-3.28319,-0.989992)
(-3.18319,-0.999135)
(-3.08319,-0.998295)
(-2.98319,-0.98748)
(-2.88319,-0.966798)
(-2.78319,-0.936457)
(-2.68319,-0.896758)
(-2.58319,-0.8481)
(-2.48319,-0.790968)
(-2.38319,-0.725932)
(-2.28319,-0.653644)
(-2.18319,-0.574824)
(-2.08319,-0.490261)
(-1.98319,-0.400799)
(-1.88319,-0.307333)
(-1.78319,-0.210796)
(-1.68319,-0.112153)
(-1.58319,-0.0123887)
(-1.48319,0.087499)
(-1.38319,0.186512)
(-1.28319,0.283662)
(-1.18319,0.377978)
(-1.08319,0.468517)
(-0.983185,0.554374)
(-0.883185,0.634693)
(-0.783185,0.70867)
(-0.683185,0.775566)
(-0.583185,0.834713)
(-0.483185,0.88552)
(-0.383185,0.927478)
(-0.283185,0.96017)
(-0.183185,0.983268)
(-0.0831853,0.996542)
(0.0168147,0.999859)
(0.116815,0.993185)
(0.216815,0.976588)
(0.316815,0.950233)
(0.416815,0.914383)
(0.516815,0.869397)
(0.616815,0.815725)
(0.716815,0.753902)
(0.816815,0.684547)
(0.916815,0.608351)
(1.01681,0.526078)
(1.11681,0.438547)
(1.21681,0.346635)
(1.31681,0.25126)
(1.41681,0.153374)
(1.51681,0.0539554)
(1.61681,-0.0460021)
(1.71681,-0.1455)
(1.81681,-0.243544)
(1.91681,-0.339155)
(2.01681,-0.431377)
(2.11681,-0.519289)
(2.21681,-0.602012)
(2.31681,-0.67872)
(2.41681,-0.748647)
(2.51681,-0.811093)
(2.61681,-0.865435)
(2.71681,-0.91113)
(2.81681,-0.947722)
(2.91681,-0.974844)
(3.01681,-0.992225)
(3.11681,-0.999693)
(3.21681,-0.997172)
(3.31681,-0.984688)
(3.41681,-0.962365)
(3.51681,-0.930426)
(3.61681,-0.889191)
(3.71681,-0.839072)
(3.81681,-0.780568)
(3.91681,-0.714266)
(4.01681,-0.640826)
(4.11681,-0.560984)
(4.21681,-0.475537)
(4.31681,-0.385338)
(4.41681,-0.291289)
(4.51681,-0.19433)
(4.61681,-0.0954289)
(4.71681,0.0044257)
(4.81681,0.104236)
(4.91681,0.203005)
(5.01681,0.299745)
(5.11681,0.393491)
(5.21681,0.483305)
(5.31681,0.56829)
(5.41681,0.647596)
(5.51681,0.720432)
(5.61681,0.78607)
(5.71681,0.843854)
(5.81681,0.893206)
(5.91681,0.933634)
(6.01681,0.964733)
(6.11681,0.986192)
(6.21681,0.997798)
(6.31681,0.999435)
(6.41681,0.991085)
(6.51681,0.972833)
(6.61681,0.94486)
(6.71681,0.907447)
(6.81681,0.860967)
(6.91681,0.805884)
(7.01681,0.742749)
(7.11681,0.672193)
f(25) = 0.991203
This is giving me the behavior that I want, however, I was trying to do the same thing using array... I'm guessing until C++ supports floating-point-constants as template arguments I'm going to have to settle with std::vector using heap allocations, instead of std::array and stack-cache friendly containers...

Adding contents to a variadic template type after instantiation

Current Source
At this point in my code I have this variadic template class:
template<typename ClassType, std::size_t... Args>
class Matrix {
private:
DimensionPack<Args...> dp;
public:
Matrix<ClassType, Args...>(){} // Default
// Public Access Members To Get Information From the DimensionPack which is based
// Not On The Type But Based On The Amount & Values Of This Template's Variadic Parameters
std::vector<unsigned int>& getDimensions() { return dp.dimensions; }
std::vector<unsigned int>& getEvenOrOdd() { return dp.even_or_odd; }
const unsigned int getNumberOfDimensions() const { return dp.total_dimensions; }
const unsigned int getTotalNumElements() const { return dp.total_elements; }
};
It uses this class and structure to do the needed calculations based on its variadic parameter list of values passed in (std::size_t...).
const unsigned int EVEN = 0;
const unsigned int ODD = 1;
struct MatrixDimensionOddOrEven {
const unsigned int even_or_odd;
explicit MatrixDimensionOddOrEven( unsigned int odd_or_even ) : even_or_odd( test( odd_or_even ) ) {}
private:
const unsigned int test( unsigned int value ) const {
if ( value == 0 ) {
std::ostringstream strStream;
strStream << __FUNCTION__ << "invalid number: " << value << " must be >= 1.";
Logger::log( strStream, Logger::TYPE_ERROR );
throw ExceptionHandler( strStream );
}
return ( ((value % 2) == 0) ? EVEN : ODD );
}
}; typedef MatrixDimensionOddOrEven MatDimOddEven;
template <std::size_t... Dims>
class DimensionPack {
public:
std::vector<std::size_t> dimensions;
std::vector<unsigned int> even_or_odd;
const std::size_t total_dimensions = sizeof...(Dims);
const std::size_t total_elements = countElements();
public:
DimensionPack() : dimensions{Dims...},
even_or_odd{ MatrixDimensionOddOrEven{Dims}.even_or_odd...} {
}
private:
std::size_t countElements() {
std::size_t val = 1; // Don't Init to 0 otherwise multiplication won't work here!
for ( std::size_t n = 0; n < dimensions.size(); n++ ) {
val *= dimensions.at( n );
}
return val;
}
};
At this point in my Matrix class I am able to successfully compile and get the results that are expected such as in these cases:
Examples Of Use:
Matrix<float, 1> mat1; // Single Element Matrix - Considered A Scalar Type
Matrix<float, 1,1...> mat1...; // Again - Single Element Matrix - Considered A Scalar Type
Matrix<float, n, m, 1, p> matNM1P; // Where n,m,p are > 1 makes that field of dimensionality flat such as a linear array or vector.
Matrix<float, 2,2> mat2x2; // creates a 2x2 Matrix with 4 elements of type float
Matrix<int, 3,3,3> mat3x3x3; // creates a 3x3x3 Volumetric Matrix with 27 elements of type int.
Matrix<type,n...> mat_multidimensional; // creates any higher order dimension of type.
I can pass them to this function to get the correct results and values:
template<typename type, std::size_t... dims>
void testMatrix( Matrix<type, dims...> matrix ) {
std::cout << "The Matrix Has " << matrix.getNumberOfDimensions() << " Total Dimensions:\n";
std::cout << "The Dimensions Are:\n";
for ( unsigned u = 0; u < matrix.getDimensions().size(); u++ ) {
std::cout << matrix.getDimensions()[u] << " ";
}
std::cout << std::endl;
std::cout << "The even and odd of each dimension are:\n";
for ( unsigned u = 0; u < matrix.getEvenOrOdd().size(); u++ ) {
std::cout << matrix.getEvenOrOdd()[u] << " ";
}
std::cout << std::endl;
std::cout << "The Matrix Has " << matrix.getTotalNumElements() << " total elements.\n\n";
}
Making my main.cpp look like this:
#include <Matrix.h>
int main() {
Matrix<float, 2, 3, 4> mat;
testMatrix( mat );
Matrix<int, 7, 9, 13, 15, 17> mat2;
testMatrix( mat2 );
Matrix<double, 255,255,255,255,255,255,255,255,255> mat9;
testMatrix( mat9 );
return 0;
}
Everything up to this point works fine and the results are expected.
The Goal
As you can see my Matrix class has a default constructor and now it is time to add contents to it. And this is where I'm sort of stuck.
For Example: If a user did the following they would have:
Matrix<float, 4,4,4> mat4x4x4; // A 3D Volumetric Matrix With 256 Elements
Matrix<float, 2,3,5> mat2x3x5; // A 3D Volumetric Matrix With 30 Elements
Matrix<float, 5,7,8,10> mat5x7x8x10; // A 4D Volumetric Matrix With 2800 Elements
Should I just accept a single vector<type> that has a fixed size that
matches the total amount of elements and create an indexing scheme?
Should I have nested <vector<vector<type>> where the amount of nested vectors matches the number of dimensions if the automation of doing such a thing can be done?
Should I create a helper structure that will nest up to 3 nested vectors then repeat that process if the automation of it can be done?
This is where I'm looking for good sound advice as to what my options should be and how it can easily be done.

Using template to generate a static lookup table

I have:
const char kLetters[] = "QWERTYUIOPASDFGHJKLZXCVBNM";
I can call kLetters[n] to obtain the nth letter of the Keyboard alphabet in O(1) time. However I will have to iterate through kLetter (taking O(n) or at least O(log n) ) time for the reverse lookup.
I would like to create a reverse lookup table as a compile-time static lookup table using templates and was wondering if there is a ways of doing this.
EDIT - as mentioned in the comments, a reverse lookup would mean I supply 'E' and get back 2. Also my alphabet example was not the best example, I would like to make no assumptions about the order. For that reason I have change the alphabet to keyboard order.
How about something like this? It lets you specify the range rather than a complete string.
#include <iostream>
template <int Start, int End, int N>
struct lookup {
static_assert(Start != End, "Can't have 0 length lookup table");
enum { value = lookup<Start+(Start < End ? 1:-1),End,N-1>::value };
};
template <int Start, int End>
struct lookup<Start,End,0> {
enum { value = Start };
};
template <int Start, int End, int V, int P=0>
struct reverse_lookup {
static_assert(Start != End, "V isn't in the range Start, End");
static_assert(Start != End || !P, "Can't have 0 length range");
enum { value = reverse_lookup<Start+(Start < End ? 1:-1),End,V,P+1>::value };
};
template <int Start, int End, int P>
struct reverse_lookup<Start,End,Start,P> {
enum { value = P };
};
int main() {
std::cout << char(lookup<'A', 'Z', 3>::value) << std::endl;
std::cout << char(lookup<'Z', 'A', 3>::value) << std::endl;
std::cout << int(reverse_lookup<'A','Z','F'>::value) << std::endl;
}
Alright, after knowing what reverse lookup is, I think you can do this:
const char kLetters[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
int get_index(char letter)
{
return letter - 'A';
}
After all, the letter A is at index 0, B at 1, C at 2... and so on. That gives enough hint.
My O(1) solution.
So far other solutions work for non-arbitrary sequence of letters, and #awoodland solution assumes that the letter whose index is to be obtainted is known at compile time which makes it less useful.
But this solution has attempted to solve both limitations; that is, it should work:
With arbitrary sequence of letters, such as
const char Letters[] = "ZBADCEWFVGHIUXJTKSLYQMROPN";
And the letters may be unknown at compile time. The function that gets the index has this signature:
int Index(char letter);
Here is the complete code which uses a technique described by # David Rodríguez in his blog:
#include <iostream>
const char Letters[] = "ZBADCEWFVGHIUXJTKSLYQMROPN";
template<char L> int Index();
template<> int Index<'Z'>() { return 0; }
template<> int Index<'B'>() { return 1; }
template<> int Index<'A'>() { return 2; }
template<> int Index<'D'>() { return 3; }
template<> int Index<'C'>() { return 4; }
template<> int Index<'E'>() { return 5; }
template<> int Index<'W'>() { return 6; }
template<> int Index<'F'>() { return 7; }
template<> int Index<'V'>() { return 8; }
template<> int Index<'G'>() { return 9; }
template<> int Index<'H'>() { return 10; }
template<> int Index<'I'>() { return 11; }
template<> int Index<'U'>() { return 12; }
template<> int Index<'X'>() { return 13; }
template<> int Index<'J'>() { return 14; }
template<> int Index<'T'>() { return 15; }
template<> int Index<'K'>() { return 16; }
template<> int Index<'S'>() { return 17; }
template<> int Index<'L'>() { return 18; }
template<> int Index<'Y'>() { return 19; }
template<> int Index<'Q'>() { return 20; }
template<> int Index<'M'>() { return 21; }
template<> int Index<'R'>() { return 22; }
template<> int Index<'O'>() { return 23; }
template<> int Index<'P'>() { return 24; }
template<> int Index<'N'>() { return 25; }
typedef int (*fptr)();
const int limit = 26;
fptr indexLookup[ limit ];
template <char L>
struct init_indexLookup {
static void init( fptr *indexLookup ) {
indexLookup[ L - 'A' ] = &Index<L>;
init_indexLookup<L-1>::init( indexLookup );
}
};
template <>
struct init_indexLookup<'A'> {
static void init( fptr *indexLookup ) {
indexLookup[ 0 ] = &Index<'A'>;
}
};
const int ignore = (init_indexLookup<'Z'>::init(indexLookup),0);
int Index(char letter)
{
return indexLookup[letter-'A']();
}
And here is the test code:
int main()
{
std::cout << Index('A') << std::endl;
std::cout << Index('Z') << std::endl;
std::cout << Index('B') << std::endl;
std::cout << Index('K') << std::endl;
}
Output:
2
0
1
16
Online demo : http://ideone.com/uzE2t
Well, that actually is two function calls: one to Index(), other to from one in the indexLookup. You can easily avoid first function call by writing (ideone):
int main()
{
std::cout << indexLookup['A'-'A']() << std::endl;
std::cout << indexLookup['Z'-'A']() << std::endl;
std::cout << indexLookup['B'-'A']() << std::endl;
std::cout << indexLookup['K'-'A']() << std::endl;
}
That looks cumbersome, but hey, we can make Index() inline:
inline int Index(char letter)
{
return indexLookup[letter-'A']();
}
That looks fine, and most likely now compiler will make it equivalent to one function call!
Simple yet O(1) solution
Wait. I just realized that the whole solution reduces to a lookup table which is initialized as:
const int indexLookup[] = {2,1,4,3,5,7,9,10,11,14,16,18,21,
25,23,24,20,22,17,15,12,8,6,13,19,0};
inline int Index(char letter)
{
return indexLookup[letter-'A'];
}
which looks unbelievably simple!
If you can use Boost and only need compile-time lookups:
using namespace boost::mpl;
typedef vector_c<char, 'A', 'B', 'C', 'D'> Chars;
// lookup by index:
std::cout << at_c<Chars, 1>::type::value << std::endl; // B
// lookup by value:
typedef find<Chars, integral_c<char, 'C'> >::type Iter;
std::cout << Iter::pos::value << std::endl; // 2
This assumes that 'Z' > 'A', but does not assume letters are contiguous. (Though it takes less memory if they are) I was tempted to put in if (numrLetters>26) conditionals so a smart compiler could use addition rather than the tables for ASCII, but then decided I didn't want to slow the code in the case of less-smart compilers.
const char kLetters[] = "ABCDEFGHJJKLMNOPQRSTUVWXYZ";
const int numLetters = sizeof(kLetters);
const char rkLetters['Z'-'A'] = {};
const int numrLetters = sizeof(rkLetters);
struct LetterInit {
LetterInit() {
for(int i=0; i<numLetters; ++i)
rkLetters[kLetters[i]-'A'] = i;
}
}LetterInitInst;
char findChar(int index) {
assert(index>=0 && index<numLetters);
return kLetters[index];
}
int findIndex(char letter) {
assert(letter>='A' && letter<='Z');
return rkLetters[letter-'A'];
}
As there are several solutions given that don't generate a table but still allow compile time lookup, here is another one
constexpr char kLetters[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
constexpr int get(char const x, int const i = 0) {
return kLetters[i] == x ? i : get(x, i + 1);
}
Use at compile time
int x[get('F')];
static_assert(sizeof(x) == sizeof(int[5]), "");
Specifying a character that doesn't exist will result in an error. If you use the function at runtime, you will get undefined behavior if you specify a character that doesn't exist. Proper checking can be added for those cases.
It yields the index of the first character found. No error is given if a character appears twice in the haystack.
If you can use c++0x (tested with gcc 4.5), this works:
#include<initializer_list>
#include<iostream>
#include<map>
constexpr int getLetterNumber(char a){ return std::map<char,int>({{'a',2},{'b',1},{'c',4}})[a]; }
int main(){
const char ch='b';
std::cout<<ch<<": "<<getLetterNumber(ch)<<std::endl;
}
constexpr enforces evaluation at compile-time.
EDIT: that solution is not correct, as pointed out. constexpr does not enfoce compile-time evaluation. This does does the lookup really at compile-time (similar to solutions posted meanwhile).
#include<iostream>
template<char C> int ch2Num();
#define CHR(c,i) template<> int ch2Num<c>(){ return i; }
CHR('a',2); CHR('b',1); /* ... */
#undef CHR
int main(void){
const char ch='b';
std::cout<<ch<<": "<<ch2Num<ch>()<<std::endl;
};

Getting template metaprogramming compile-time constants at runtime

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.