I have a class template
template<typename U, ...more specialization... > class A {
static_assert(std::is_arithmetic<U>::value, "U type must be arithmetic");
public:
const std::set<U> fibonacci = ???; //May be any structure with iterators, not necessarily set
...more code...
};
"fibonacci" has to be a structure, created in compile-time, containing all fibonacci numbers of type U, from 1 to maximal possible fibonacci number smaller than max_U. Since I don't know what the type U is (I only know that it's arithmetic), I have to somehow check how many numbers I can generate. I tried many different approaches, but none of them worked.
For example, I tried doing something like this:
template <typename U, size_t N>
constexpr U Fib() {
if (N <= 1) return 1; //was N < 1 (incorrect)
return Fib<U, N-1>() + Fib<U, N-2>();
}
template <typename U, size_t n, typename ... Args>
constexpr std::set<U> make_fibonacci_set(Args ...Fn) {
if (Fib<U, n>() <= Fib<U, n-1>()) {
return std::set<U> {{Fn...}};
}
else {
return make_fibonacci_set<U, n+1>(Fn..., Fib<U, n>());
}
}
at class A...: const std::set<U> fibonacci = make_fibonacci_set<U, 2>(1);
But I get an error: "fatal error: recursive template instantiation exceeded maximum depth of 256".
Due to a quirk of the language,
Fib()andmake_fibonacci_set(), as written, will have infinite recursion (specifically, to my understanding, the problem is that while only one branch is chosen, both are evaluated; this causes the compiler to instantiate the templates required by the recursive branch, even when the other is chosen, generating infinite instantiations). To my understanding,constexpr ifwould resolve this nicely; however, I don't currently have access to any compilers that support it, so this answer will instead rework the former to rely on a helper (so introspection can be performed, and to aid in making a fully compile-time container class), and use SFINAE to break the latter into two distinct functions (to hide each one'sreturnstatement from the other).First, before we get to the actual code, we'll want a helper macro if MSVC compatibility is desired, due to its (as of Nov.29, 2016) incomplete support of expression SFINAE.
And now, the code itself. First,
Fib()'s helper.This allows us to define
Fib()trivially, and provide a convenient means of introspection.And now, for
make_fibonacci_set(). I changed the way this one works a bit; specifically, I made it a wrapper for another function calledmake_fibonacci_seq(), which is a more generic version that works for any valid container.This can cleanly assign the sequence to a
std::set, or to other types (such asstd::vector.If you want
fibonaccito be created at compile time, however, it has to be aLiteralType, a type that can be created at compile time.std::set<T>is not aLiteralType, hence it can't be used for a compile-time Fibonacci sequence. Therefore, if you want to guarantee that it'll be constructed at compile time, you'll want your class to use a compile-time constructible container, such asstd::array. Conveniently,make_fibonacci_seq()there lets you specify the container, so...See it in action here (original link here).