2
votes

How to create const std::array containing following values f(0), f(1), ..., f(N-1) where f is any function: static constexpr size_t f(int index)? When I know exactly N I can obviously write

const std::array<size_t, 5> a = {f(0), f(1), f(2), f(3), f(4)}
4
Do you have C++14 support? - Brian Bi
show us what you've already tried rather than expect SO to write the code for you from scratch - johnbakers
@Brian Yes, even c++17. - adbeno
@hellofunk I googled it and didn't find anything useful. I don't see the point of showing my code which doesn't work. - adbeno
@BenonAdamczyk the point of showing your code that doesn't work is actually the entire point of SO. If your code worked, you wouldn't post the question. Then, you'd learn more about where your coding went wrong, and others can help you understand your thought process. It is generally frowned upon to ask an open-ended question where you expect other people to write your code for you entirely. - johnbakers

4 Answers

4
votes

A general technique for creating constants that require arbitrarily complex initialization is to simply write a function that returns the value you want, and then call that in the constant's initializer. For example:

template <typename T, size_t N>
array<T, N> init_from_f() {
    array<T, N> a;
    for (size_t i = 0; i < N; ++i)
        a[i] = f(i);
    return a;
}

const auto const_array = init_from_f<sometype, 42>();
3
votes

It might need polishing but that's what I thought:

template <std::size_t... ns, typename Fn>
auto fill_helper(std::integer_sequence<std::size_t, ns...>, Fn&& fn) -> std::array<decltype(fn(std::size_t())), sizeof...(ns)>  {
    return {{fn(ns)...}};
} 

template <std::size_t N, typename Fn>
auto fill(Fn&& fn) {
    using seq = std::make_integer_sequence<std::size_t, N>;
    return fill_helper(seq(), std::forward<Fn>(fn));    
}

int main() {

    auto plus5 = [](std::size_t index) {
        return index + 5;
    };

    auto const as = fill<5>(plus5);
    for (auto&& a: as)
        std::cout << a;

}

The advantage is that you are initializing the array with the proper values, rather than first initializing and then assigning.

2
votes

You could also do something like this if you want to const-initialize it without creating an external function:

void SomeFunction() {

    const auto my_array = [](){
        auto a = array<SomeType, N>();
        for (size_t i = 0; i < a.size(); ++i)
            a[i] = f(i);
        return a;
    }(); // <-- Note that the lambda executes right away

    DoSomeStuff(my_array);
}
1
votes

Use a lambda and std::generate:

#include<array>
#include<algorithm> // generate
#include<cassert>
#include<iostream>

int f(int i){return i*i;}

int main(){
    const std::array<int, 5> a = []{
        std::array<int, 5> a;
        int n = 0;
        std::generate(a.begin(), a.end(), [&n]{ return f(n++); });
        return a;
    }();
    assert( a[4] == 16 );
}

http://coliru.stacked-crooked.com/a/60e2ec92e648519d