Search code examples
c++constexprstdarray

Is it possible to initialize constexpr std::array member in a programtic way


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.


Solution

  • 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.