3

Lets assume I want to write struct that has a member constexpr std::array that contains first N fibs, where N is a template argument.

Something like this but with vals being avaliable at compile time:

template <int N>
struct first_n_fibs {
    static_assert(N>0);
    static const std::array<int, N> vals;
    static std::array<int, N> init_fibs(){
        std::array<int,N> result;
        if (N==1) {
            return std::array<int,N>{1};
        } else {
            result[0]=1;
            result[1]=1;
            for(int i =2; i<N;++i) {
                result[i]=result[i-2]+result[i-1];
            }
        }
        return result;
    }
};

template<int N>
const std::array<int, N> first_n_fibs<N>::vals=init_fibs();


int main(){
    std::cout << first_n_fibs<2>::vals.back() << std::endl;
    std::cout << first_n_fibs<5>::vals.back() << std::endl;
    std::cout << first_n_fibs<6>::vals.back() << std::endl;
}

I suspect there is no workaround since std::array constructors are not constexpr, so if somebody knows any workarounds involving C arrays or boost I would be happy with that.

NoSenseEtAl
  • 28,205
  • 28
  • 128
  • 277
  • I'd like to know why you want it to be `std::array`. Besides, `first_n_fibs` create a lot of instance while all these are (prefix) equal. – apple apple May 10 '18 at 00:52
  • because IDK how to operate on C array at compile time. As for instances and duplication: I know about that, but in some cases it is worth the cost. – NoSenseEtAl May 10 '18 at 00:56
  • if you work on C array than any prefix-equal const `first_n_fibs` can be represent by single pointer to the longest array. can you provide your use case? – apple apple May 10 '18 at 01:02
  • otherwise if you want to get only the `nth-fib` at compile time a `std::array` may be overkill. – apple apple May 10 '18 at 01:08

2 Answers2

7

You don't need anything special, constexpr function requirements are very relaxed these days:

#include <iostream>
#include <array>

template <int N> constexpr std::array<int, N> first_n_fibs()
{
    std::array<int, N> ret{};
    ret[0] = 0;
    if (N == 1) return ret;
    ret[1] = 1;
    for (int i = 2; i < N; i++)
        ret[i] = ret[i-2] + ret[i-1];
    return ret;
}

int main()
{
    constexpr auto a = first_n_fibs<3>();
}

(try it live)


std::array constructors are not constexpr

Apparently it has no user-defined constructors at all, so nothing stops its construction from being constexpr.

HolyBlackCat
  • 78,603
  • 9
  • 131
  • 207
  • nice workaround, but in general I prefer to have it inside class, since having a bunch of "getter" functions is not nice(and may be slower) from design point of view. – NoSenseEtAl May 09 '18 at 23:45
  • Actually you are right, gcc was giving me lame error, all I did was that I did not initializer ret with {} like you did. – NoSenseEtAl May 10 '18 at 01:16
2

You can use immediately called lambda:

struct foo {
    static constexpr auto arr = []{
        std::array<int, 6> a{};

        for (auto& e : a) {
            // stuff
        }

        return a;
    }();
};

But as HolyBlackCat said, std::array is constexpr constructible, since it has no defined constructor, only compiler defined ones.

Here's live example at coliru

Guillaume Racicot
  • 39,621
  • 9
  • 77
  • 141
  • "std::array is totally constexpr constructible" IDK the language terms, but when I put constexpr in front of member it does not compile :) – NoSenseEtAl May 10 '18 at 01:02
  • "error: constexpr static data member 'vals' must have an initializer" – NoSenseEtAl May 10 '18 at 01:03
  • @NoSenseEtAl when making a variable constexpr, you must give it a value, as your compiler is telling you. It needs an initializer. Alternatively, you can put your definition inline and mark the definition add constexpr. – Guillaume Racicot May 10 '18 at 01:04
  • Plese see my other comments, bug was me not writing {} when initializing array in my function, and GCC giving me silly error. – NoSenseEtAl May 10 '18 at 01:17
  • I still upvoted your answer, I am sorry you wasted time on helping me, but really error smelled like constexpr problem(it contained "is not usable as a constexpr function because") – NoSenseEtAl May 10 '18 at 01:18