Quantcast
Channel: GameDev.net
Viewing all articles
Browse latest Browse all 17825

Remove types from std::tuple

$
0
0
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<typename Arg> struct StripTuple { using Type = Arg; }; template<typename Arg, typename... Args> struct StripTuple<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> struct StripTuple<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: template<typename Type> struct AttributeSupplier<Type, sys::EnableIf<core::IsTypeSystemType<Type> && !core::IsObject<Type>, void>> { static Type GetAttribute(core::ConstVariableView value) { return value.GetValue<Type>(); } static core::TypeId GetTypeId(void) { return core::generateTypeId<Type>(); } }; 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: struct UnderlyingTypeHelper { using InvalidType = void; template<typename Arg, typename Enable = void> struct Helper { }; // helper for recursion template<typename Arg> using HelperType = typename Helper<Arg>::type; private: // if the arguments trait defines a type-id, we're done template<typename Arg> struct Helper<Arg, sys::EnableIf<HasAttributeTypeId<Arg>, void>> { using type = Arg; }; // values not useable as attributes are meant to be removed/set to void template<typename Arg> struct Helper<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 values template<typename Arg> struct Helper<Arg, sys::EnableIf<!IsTuple<Arg> && CanBeAttribute<Arg> && !HasAttributeTypeId<Arg>, void>> { using type = HelperType<AttributeFunctionArgs<Arg>>; }; // tuple => unfold function arguments template<typename... Args> struct Helper<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

Viewing all articles
Browse latest Browse all 17825

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>