4

I have a template class that contains a single member array of compile-time constant length. I want this array to be constant, but initializing it based on constructor-provided input is proving difficult:

struct Input {
    int value;
};

template<size_t Size>
struct Foo {
    int const myVals[Size];
    Foo(std::array<Input, Size> const &in)
        : myVals{ in[0].value, in[1].value, /* How many times? */ } {
    }
}

Since I don't know the size of the array, I don't know how many values with which to initialize myVals. The following code works, but I question whether it is the best approach:

template<size_t Size>
struct Foo {
    std::array<int, Size> const myVals;
    Foo(std::array<Input, Size> const &in)
        : myVals{ toIntArray(in) } {
    }
private:
    static std::array<int, Size> toIntArray(std::array<Input, Size> const &in) {
        std::array<int, Size> result;
        for (size_t i{ 0 }; i < Size; ++i) {
            result[i] = in[i].value;
        }
        return result;
    }
}

Is there a more succinct, or generally more accepted way to populate the values of a constant member array?

2
  • @JeJo When I try that in VS2017u2, I get one of three errors (one when myVals has type int[], one when initializing with myVals{in}, and finally, one when initializing with myVals(in)). Which compiler are you using where an std::array can be initialized by a type with different template parameters? Commented Apr 29, 2019 at 19:06
  • Sorry I was wrong about that. That won't work. However, the way you followed is good.(IMHO) That should be also done by some template magic though. ;). Unpack the std::array<Input, Size> -> cast to int, if needed -> make tuple of elements -> move to member array. Commented Apr 30, 2019 at 7:22

1 Answer 1

2

You can use std::index_sequence to get the indices of the array as a non-type template parameter pack. Then you can use a parameter pack expansion.

template<size_t Size>
struct Foo {
    int const myVals[Size];
    Foo(std::array<Input, Size> const &in)
        : Foo(in, std::make_index_sequence<Size>()) { }
    private:
    template<size_t... Is>
    Foo(std::array<Input, Size> const &in, std::index_sequence<Is...>)
        : myVals{in[Is].value...} { }
}

Using a helper template with a size_t... Is pack and a std::index_sequence<Is...> argument is a common pattern for handling fixed-size indexable containers. The index_sequence doesn't actually do anything; it's just a proxy so that the Is template arguments can be deduced. E.g. if you check on Godbolt it appears to totally evaporate under -O1.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.