@@ -395,6 +395,38 @@ struct TSRemoveIndicesImpl<TypeList<T, Ts...>, First, Last, Idx>
395395 using type = typename ThisList::template Append<NextList>;
396396};
397397
398+ // / @brief Transform a @c TypeList, converting each type into a new type based
399+ // / on a transformation struct @c OpT.
400+ // / @details This implementation iterates through each type in a @c TypeList
401+ // / and builds a new @c TypeList where each element is resolved through
402+ // / a user provided converter which provides a @c Type definition.
403+ // / @tparam OpT User struct to convert each type
404+ // / @tparam Ts Remaining types in the @c TypeList
405+ template <template <typename > class OpT , typename ... Ts> struct TSTranformImpl ;
406+
407+ // / @brief Partial specialization for an empty @c TypeList
408+ // / @tparam OpT User struct to convert each type
409+ template <template <typename > class OpT >
410+ struct TSTranformImpl <OpT> {
411+ using type = TypeList<>;
412+ };
413+
414+ // / @brief Implementation of TSTranformImpl. See fwd declaration for details.
415+ // / @tparam OpT User struct to convert each type
416+ // / @tparam Ts Remaining types in the @c TypeList
417+ // / @tparam T Current type being converted
418+ template <template <typename > class OpT , typename T, typename ... Ts>
419+ struct TSTranformImpl <OpT, T, Ts...> {
420+ private:
421+ using NextList = typename TSTranformImpl<OpT, Ts...>::type;
422+ public:
423+ // Invoke Append for each type to match the behaviour should OpT<T> be a
424+ // TypeList<>
425+ using type = typename TSTranformImpl<OpT>::type::template
426+ Append<OpT<T>>::template
427+ Append<NextList>;
428+ };
429+
398430
399431template <typename OpT> inline void TSForEachImpl (OpT) {}
400432template <typename OpT, typename T, typename ... Ts>
@@ -404,6 +436,39 @@ template<template <typename> class OpT> inline void TSForEachImpl() {}
404436template <template <typename > class OpT , typename T, typename ... Ts>
405437inline void TSForEachImpl () { OpT<T>()(); TSForEachImpl<OpT, Ts...>(); }
406438
439+
440+ // / @brief Partial apply specialization for an empty @c TypeList
441+ // / @tparam OpT User functor to apply to the first valid type
442+ // / @tparam BaseT Type of the provided obj
443+ // / @tparam T Current type
444+ // / @tparam Ts Remaining types
445+ template <typename OpT, typename BaseT, typename T, typename ...Ts>
446+ struct TSApplyImpl { static bool apply (BaseT&, OpT&) { return false ; } };
447+
448+ // / @brief Apply a unary functor to a provided object only if the object
449+ // / satisfies the cast requirement of isType<T> for a type in a TypeList.
450+ // / @note Iteration terminates immediately on the first valid type and true
451+ // / is returned.
452+ // / @tparam OpT User functor to apply to the first valid type
453+ // / @tparam BaseT Type of the provided obj
454+ // / @tparam T Current type
455+ // / @tparam Ts Remaining types
456+ template <typename OpT, typename BaseT, typename T, typename ...Ts>
457+ struct TSApplyImpl <OpT, BaseT, TypeList<T, Ts...>>
458+ {
459+ using CastT =
460+ typename std::conditional<std::is_const<BaseT>::value, const T, T>::type;
461+
462+ static bool apply (BaseT& obj, OpT& op)
463+ {
464+ if (obj.template isType <T>()) {
465+ op (static_cast <CastT&>(obj));
466+ return true ;
467+ }
468+ return TSApplyImpl<OpT, BaseT, TypeList<Ts...>>::apply (obj, op);
469+ }
470+ };
471+
407472} // namespace internal
408473
409474// / @endcond
@@ -477,6 +542,8 @@ struct TypeList
477542 using Unique = typename typelist_internal::TSRecurseAppendUniqueImpl<ListT, Ts...>::type;
478543
479544 // / @brief Append types, or the members of another TypeList, to this list.
545+ // / @warning Appending nested TypeList<> objects causes them to expand to
546+ // / their contained list of types.
480547 // / @details Example:
481548 // / @code
482549 // / {
@@ -552,8 +619,29 @@ struct TypeList
552619 template <size_t First, size_t Last>
553620 using RemoveByIndex = typename typelist_internal::TSRemoveIndicesImpl<Self, First, Last>::type;
554621
622+ // / @brief Transform each type of this TypeList, rebuiling a new list of
623+ // / converted types. This method instantiates a user provided Opt<T> to
624+ // / replace each type in the current list.
625+ // / @warning Transforming types to new TypeList<> objects causes them to expand to
626+ // / their contained list of types.
627+ // / @details Example:
628+ // / @code
629+ // / {
630+ // / // Templated type decl, where the type T will be subsituted for each type
631+ // / // in the TypeList being transformed.
632+ // / template <typename T>
633+ // / using ConvertedType = typename openvdb::PromoteType<T>::Next;
634+ // /
635+ // / // Results in: openvdb::TypeList<Int64, double>;
636+ // / using PromotedType = openvdb::TypeList<Int32, float>::Transform<ConvertedType>;
637+ // / }
638+ // / @endcode
639+ template <template <typename > class OpT >
640+ using Transform = typename typelist_internal::TSTranformImpl<OpT, Ts...>::type;
641+
555642 // / @brief Invoke a templated class operator on each type in this list. Use
556643 // / this method if you only need access to the type for static methods.
644+ // / @details Example:
557645 // / @code
558646 // / #include <typeinfo>
559647 // /
@@ -593,6 +681,46 @@ struct TypeList
593681 // / to use the same object for each type.
594682 template <typename OpT>
595683 static void foreach (OpT op) { typelist_internal::TSForEachImpl<OpT, Ts...>(op); }
684+
685+ // / @brief Invoke a templated, unary functor on a provide @c obj of type
686+ // / @c BaseT only if said object is an applicable (derived) type
687+ // / also contained in the current @c TypeList.
688+ // / @details This method loops over every type in the type list and calls
689+ // / an interface method on @c obj to check to see if the @c obj is
690+ // / interpretable as the given type. If it is, the method static casts
691+ // / @c obj to the type, invokes the provided functor with the casted type
692+ // / and returns, stopping further list iteration. @c obj is expected to
693+ // / supply an interface to validate the type which satisfies the
694+ // / prototype:
695+ // / @code
696+ // / template <typename T> bool isType()
697+ // / @endcode
698+ // /
699+ // / A full example (using dynamic_cast - see Grid/Tree implementations
700+ // / for string based comparisons:
701+ // / @code
702+ // / struct Base {
703+ // / virtual ~Base() = default;
704+ // / template<typename T> bool isType() { return dynamic_cast<const T*>(this); }
705+ // / };
706+ // / struct MyType1 : public Base { void print() { std::cerr << "MyType1" << std::endl; } };
707+ // / struct MyType2 : public Base { void print() { std::cerr << "MyType2" << std::endl; } };
708+ // /
709+ // / using MyTypeList = TypeList<MyType1, MyType2>;
710+ // / Base* getObj() { return new MyType2(); }
711+ // /
712+ // / std::unique_ptr<Base> obj = getObj();
713+ // / // Returns 'true', prints 'MyType2'
714+ // / const bool success =
715+ // / MyTypeList::apply([](const auto& type) { type.print(); }, *obj);
716+ // / @endcode
717+ // /
718+ // / @note The functor object is passed by value. Wrap it with @c std::ref
719+ // / pass by reference.
720+ template <typename OpT, typename BaseT>
721+ static bool apply (OpT op, BaseT& obj) {
722+ return typelist_internal::TSApplyImpl<OpT, BaseT, Self>::apply (obj, op);
723+ }
596724};
597725
598726
0 commit comments