Recommended Posts

So what I want to do sounds pretty simple, but I just can't figure it out: I want to remove all types with a certain characteristic from a tuple. For this example, the condition is actually simple: I want to strip all occurances of "void", so

std

std::tuple<bool,void,int,void,void,float,void>;

becomes:

std::tuple<bool,int,float>;

I ususally don't have a problem with crazy template-code, but this is just above me. I mean, I know how to split the tuple-declaration into elements, but cannot figure out how to just remove one element while leaving the others intact:

template<typenameArg>structStripTuple{usingType=Arg;};template<typenameArg,typename...Args>structStripTuple<std::tuple<Arg,Args...>>{using type = std::tuple<Arg,Args...>>;// ignores StripTuple for all other call; call to StripTuple would be infinite recursion};template<typename...Args>structStripTuple<std::tuple<void,Args...>>{using type =StripTuple<Args...>>;};

Any simple solutions (remove-condition = void can be used; doesn't have to work with SFINEA if it doesn't need to)?

Alternatively, and to give some context, I'd also be happy not to buld the tuple to have voids to begin with. Though I also can't seem to figure that out for the life of me, and I actually belive it would make the code even more complex than just splitting it into two steps, but let me describe the problem (but beware, if you have a solution that works on the requirements above post this before, as I think the actual problem might be hard to get across for me):

For my script-function binding, I recently refactored the type-system to handle types with a specializable trait class, which ie. can be defined for value-types:

The important thing about it, which leads to my "problem", is that this works recursively - when the trait is used, it will unfold the argument-list of the "GetAttributes"-method and forward the aquisition to the next AttributeSupplier. As with GetTypeId, this can be omitted, in which case it will do the same thing - aquire the type-id by unfolding the argument-list and checking those types' suppliers.

So what the code that requires stripping the tuple of voids does, is try to access the underlying type of any type(s) it receives, by performing the type-unfolding. Thats necessary for multiple reason, for once the type-system can define a runtime-specific value (ie. EntityHandle which is aquired via EntityID), so the underlying type should be "EntityID". Also, to simplify parsing of a function-declaration, this should allow me to pack all argument-type-ids into a single tuple, unfolding all types (which can also include pair/tuple itself). Stripping the void is for system-supplied values - those do not have a type-id, even after unfolding the entire chain of types, so for the UnderlyingType-definition, they need to be removed. So ie., for a function-signature "void f(int, Entity&, DeltaTime, std::pair<float, bool>)", this should result in the tuple-type "std::tuple<int, Entity&, float, bool>". which is done with this code:

structUnderlyingTypeHelper{usingInvalidType=void;template<typenameArg,typenameEnable=void>structHelper{};// helper for recursiontemplate<typenameArg>usingHelperType=typenameHelper<Arg>::type;private:// if the arguments trait defines a type-id, we're donetemplate<typenameArg>structHelper<Arg, sys::EnableIf<HasAttributeTypeId<Arg>,void>>{using type =Arg;};// values not useable as attributes are meant to be removed/set to voidtemplate<typenameArg>structHelper<Arg, sys::EnableIf<!CanBeAttribute<Arg>,void>>{using type =InvalidType;// !!! here's the out to "void" => this would need to somehow not make it into the tuple created below};// forwarded type-id => container-structs, runtime-mapped valuestemplate<typenameArg>structHelper<Arg, sys::EnableIf<!IsTuple<Arg>&&CanBeAttribute<Arg>&&!HasAttributeTypeId<Arg>,void>>{using type =HelperType<AttributeFunctionArgs<Arg>>;};// tuple => unfold function argumentstemplate<typename...Args>structHelper<std::tuple<Args...>>{using type = std::tuple<HelperType<Args>...>;};};

The last specialization is responsible for building the output-tuple, while the others are for eigther recursively unfolding the arguments (AttributeFunctionArgs stores the GetAttribute-signature as a tuple), and selecting when to stop with a type-id-supplied Arg, or just "void" out if we reach a point where Arg is not a valid attribute anymore.

So yeah, here's some context, and if anyone feels like torturing their brain around some stupid template-code and comes up with a ingenious solution to that, I wouldn't be unhappy. But I doubt that happens, so a solution to the problem stated way above is already more then enough. Thanks

Damn, thats a lot of boilerplate-code though, all of which is needed from my testings. Well, if someone still wants to wrap their head around the underlying algorithmn & propose some better alternative, I'm all for it

Share this post

Link to post

Share on other sites

Ah, thats much nicer than my solution, even after I simplified it a bit I'll just have to modify it a bit, as I also need to collapse all tuples recursively - so std::tuple<int, std::tuple<bool, void>, float> becomes std::tuple<int, bool, float>. Thats currently done by this monstrosity: