How to expand Tuple to Match Arguments Provided?

175 views Asked by At

I have a function that (after simplifying the logic) takes the form

std::tuple<font_heap, font_heap> get_font_heaps(std::vector<uint8_t> const& a, std::vector<uint8_t> const& b) {
    return std::make_tuple(get_font_heap_from_data(a), get_font_heap_from_data(b));
}

I'd like to templatize this function so that it can handle as many or as few datasets as the user passes in.

auto [serif, sansserif, monospace] = get_font_heaps(serif_data, sansserif_data, monospace_data);
auto [comic_sans] = get_font_heaps(comic_sans_data);

I've started by trying to rewrite the logic like so:

template<typename ... FontDatas>
auto get_font_heaps(std::vector<uint8_t> const& data, FontData&& ...datas) {
    if constexpr(sizeof...(FontDatas) == 0) {
        return std::make_tuple(get_font_heap_from_data(data));
    else {
        return std::make_tuple(get_font_heap_from_data(data), get_font_heaps(std::forward<FontDatas>(datas)...);
}

But obviously, even if this compiles, it doesn't quite do what I want: it creates a nested tuple out of this code, in the form std::tuple<font_heap, std::tuple<font_heap, std::tuple<font_heap>>>, whereas what I want is std::tuple<font_heap, font_heap, font_heap>

How can I rewrite this logic to do what I intend? I'm using MSVC 2017.3, so I have access to a lot of C++17 features, but not Fold Expressions (which I suspect would simplify the logic greatly).

1

There are 1 answers

1
Barry On BEST ANSWER

Seems like you just want

template <class... Data>
auto get_font_heaps(Data const&... d) {
    return std::make_tuple(get_font_heap_from_data(d)...);
}

That's C++14. We could even make it C++11 with an alias that discards its input:

template <class T>
using font_heap_t = font_heap;

template <class... Data>
std::tuple<font_heap_t<Data>...>
get_font_heaps(Data const&... d) {
    return std::make_tuple(get_font_heap_from_data(d)...);
}

T.C. makes a good point in the comments. Since all our types are the same, we should return a std::array instead of a std::tuple:

template <class... Data>
std::array<font_heap, sizeof...(Data)>
get_font_heaps(Data const&... d) {
    return {{get_font_heap_from_data(d)...}};
}