meatandmahjong
meatandmahjong

Reputation: 105

Filtering nested dynamic tuple (dynamic tuple of tuples)

I have a sort of dynamic tuple structure:

template <typename... Elems> //Should only be tuples
class DynamicTuple {
    vector<byte> data; //All data is stored contiguously
    vector<tuple<size_t,size_t>> element_table; //First element is offset into the data vector; second is which index of the parameter pack holds the stored type.
    /* ... */ 
}

Now I want to be able to filter out all tuples that contain a list of types.

template <typename... Ts>
vector<tuple<Ts&...>> filter() {
    vector<tuple<Ts&...>> result;
    for (auto it : element_table) {
        auto [offset, type] = it;
        // ???
    }
}

Here I need to be able to check if the type in the Nth index of the "Elems" parameter pack is a tuple that contains all the types in the "Ts" parameter pack. If it does, I want to push back a tuple containing those values.

Intuitively I want to use the "type" value to get the type from the "Elems" parameter pack, and use a has_type structure like the one from this answer: https://stackoverflow.com/a/41171291/11463887 Something like:

((has_type<Ts, tuple_element<type, tuple<Elems...>>::type>&& ...))

However this doesn't work, since "type" is not a compile-time constant expression. Is there a way to get around this?

Upvotes: 0

Views: 176

Answers (2)

walnut
walnut

Reputation: 22162

With the has_type that you already have, you can in the same manner define a type_subset testing whether all types are contained in the tuple:

template <typename Ts, typename Tuple>
struct type_subset;

template <typename... Ts, typename... Us>
struct type_subset<std::tuple<Ts...>, std::tuple<Us...>>
    : std::conjunction<has_type<Ts, std::tuple<Us...>>...> {};

and then you probably want to find the correct type matching your type index by iterating over the parameter pack and the corresponding indices:

size_t i = 0;
bool match = ((type == i++ && type_subset<std::tuple<Ts...>, Elems>::value) || ...);

Make sure to reset i to 0 before each execution of the fold expression. You might want to put the whole thing in a lambda or function to separate the i and to reuse this with other conditions.


Maybe better performing is to save the possible results to an array at compile-time, and then index into it at runtime:

constexpr static std::array matches{type_subset<std::tuple<Ts...>, Elems>::value...};
bool match = matches[type];

In either case you need to make sure that type < sizeof...(Elems). In the second variant especially you will have undefined behavior otherwise (if you don't use .at instead of []).

Upvotes: 2

darune
darune

Reputation: 11145

However this doesn't work, since "type" is not a compile-time constant expression. Is there a way to get around this?

It's not possible to return a different type based on a runtime value.

You either have to resort to something that can be evaluated at runtime (eg. use a vector) OR have the input be compile time constant.

A runtime solution could use type_id or similiar.

Upvotes: 1

Related Questions