Home > Software design >  Const array initalize from other const array
Const array initalize from other const array

Time:09-03

const char DICTIONARY[][6] = {
    "apple",
    "sands"
};

class LetterSet {
    public:
        unsigned int bitfield;
        LetterSet(const char letters[5]) {};
};

const LetterSet words[] = {
    LetterSet(DICTIONARY[0]),
    LetterSet(DICTIONARY[1]),
};

How can I modify the code above to work in the case where DICTIONARY is too large to feasibly write out by hand? Specifically, I do not understand how to initalize the words array in any way that is not a runtime loop-through and create each element.

CodePudding user response:

Might not be needed by Carson, but for those looking for a way to transform an array elements to another type at compile time, it's possible using helper templates and std::array. An example:

template<class T, std::size_t...Is>
auto transform_array_impl(auto&& array, std::index_sequence<Is...>)
{
    return std::array<T, sizeof...(Is)>
    {{
        (T(array[Is]))...
    }};
}

template<class T, class U, std::size_t N>
auto transform_array(const U (&array)[N])
{
    return transform_array_impl<T>(array, std::make_index_sequence<N>());
}

const auto words = transform_array<LetterSet>(DICTIONARY);

CodePudding user response:

Seems to me the simple solution is to use a std::vector instead of an array. Then you can do the initialisation in one line.

const std::vector<LetterSet> words(std::begin(DICTIONARY), std::end(DICTIONARY));

CodePudding user response:

Not sure how to do that for an arbitrary variable, but in context of a function template such argument can be built with template recursion:

template<typename T, std::size_t Pos = 0, std::size_t Size, typename F, typename ...Elements>
void makeArray(const F(&arr)[Size], const Elements&... elements) {
    if constexpr(Pos < Size) {
        makeArray<T, Pos   1>(arr, elements..., arr[Pos]);
    } else {
        const T newArray[] { T(elements)... };
        std::cout << sizeof(newArray) << std::endl;
    }
}

You can extend it to a class member, but unfortunately such a recursion doesn't quite work for constructors and you will have to deal with a free function factory (named constructor idiom neither works if you don't want to specify all the template arguments in advance):

template<typename Type, std::size_t Size>
class my_class {
    const Type array[Size];
    
    template<typename... Elements>
    my_class(const Elements&... elements): array{ elements... } {}
    
    template<typename T, std::size_t Pos, std::size_t S, typename F, typename ...Elements>
    friend my_class<T, S> makeMyClass(const F(&arr)[S], const Elements&... elements);
    
};

template<typename T, std::size_t Pos = 0, std::size_t S, typename F, typename ...Elements>
my_class<T, S> makeMyClass(const F(&arr)[S], const Elements&... elements) {
    if constexpr(Pos < S) {
        return makeMyClass<T, Pos   1>(arr, elements..., arr[Pos]);
    } else {
        return my_class<T, S>{ elements... };
    }
}

This is how it looks from the client code:

int main(){
    
    const char DICTIONARY[][6] = {
        "apple",
        "sands"
    };
    
    const my_class instance = makeMyClass<LetterSet>(DICTIONARY);
    
    return 0;
}
  • Related