diff --git a/include/podio/Association.h b/include/podio/Association.h index 52ccfa8f4..dc4595373 100644 --- a/include/podio/Association.h +++ b/include/podio/Association.h @@ -128,6 +128,67 @@ class AssociationT { m_obj->m_to = new detail::GetDefT(value); } + /** + * Templated version for getting an element of the association by type. Only + * available for Associations where FromT and ToT are **not the same type**, + * and if the requested type is actually part of the Association. It is only + * possible to get the immutable types from this. Will result in a compilation + * error if any of these conditions is not met. + * + * @tparam T the desired type + * @returns T the element of the Association + * */ + template && detail::isFromOrToT>> + T get() const { + if constexpr (std::is_same_v) { + return getFrom(); + } else { + return getTo(); + } + } + + /** + * Tuple like index based access to the elements of the Association. Returns + * only immutable types of the associations. This method enables structured + * bindings for Associations. + * + * @tparam Index an index (smaller than 3) to access an element of the Association + * @returns Depending on the value of Index: + * - 0: The From element of the Association + * - 1: The To element of the Association + * - 2: The weight of the Association + */ + template > + auto get() const { + if constexpr (Index == 0) { + return getFrom(); + } else if constexpr (Index == 1) { + return getTo(); + } else { + return getWeight(); + } + } + + /** + * Templated version for setting an element of the association by type. Only + * available for Associations where FromT and ToT are **not the same type**, + * and if the requested type is actually part of the Association. Will result + * in a compilation error if any of these conditions is not met. + * + * @tparam T type of value (**infered!**) + * @param value the element to set for this association. + */ + template < + typename T, bool Mut = Mutable, + typename = std::enable_if_t && detail::isMutableFromOrToT>> + void set(T value) { + if constexpr (std::is_same_v) { + setFrom(std::move(value)); + } else { + setTo(std::move(value)); + } + } + /// check whether the object is actually available bool isAvailable() const { return m_obj; diff --git a/include/podio/detail/AssociationFwd.h b/include/podio/detail/AssociationFwd.h index a1291dc07..f52ae6bda 100644 --- a/include/podio/detail/AssociationFwd.h +++ b/include/podio/detail/AssociationFwd.h @@ -1,6 +1,8 @@ #ifndef PODIO_DETAIL_ASSOCIATIONFWD_H #define PODIO_DETAIL_ASSOCIATIONFWD_H +#include "podio/utilities/TypeHelpers.h" + #include #include #include @@ -36,6 +38,20 @@ namespace detail { template using GetCollT = typename GetCollType::type; + /** + * Variable template to for determining whether T is either FromT or ToT. + * Mainly defined for convenience + */ + template + static constexpr bool isFromOrToT = detail::isInTuple>; + + /** + * Variable template to for determining whether T is either FromT or ToT or + * any of their mutable versions. + */ + template + static constexpr bool isMutableFromOrToT = detail::isInTuple, GetMutT>>; + /** * Get the collection type name for an AssociationCollection * @@ -104,4 +120,14 @@ using AssociationMutableCollectionIterator = AssociationCollectionIteratorT +struct tuple_size> : std::integral_constant {}; + +/// Specialization for enabling structure bindings for Associations +template +struct tuple_element> : tuple_element> {}; +} // namespace std + #endif // PODIO_DETAIL_ASSOCIATIONFWD_H diff --git a/tests/associations.cpp b/tests/associations.cpp index 782e760dc..c728ba431 100644 --- a/tests/associations.cpp +++ b/tests/associations.cpp @@ -131,6 +131,38 @@ TEST_CASE("Association basics", "[associations]") { } } +TEST_CASE("Associations templated accessors", "[associations]") { + ExampleHit hit; + ExampleCluster cluster; + + TestMutA assoc; + assoc.set(hit); + assoc.set(cluster); + assoc.setWeight(1.0); + + SECTION("Mutable Association") { + REQUIRE(hit == assoc.get()); + REQUIRE(cluster == assoc.get()); + + const auto [h, c, w] = assoc; + REQUIRE(h == hit); + REQUIRE(c == cluster); + REQUIRE(w == 1.0); + } + + SECTION("Immutable association") { + TestA a{assoc}; + + REQUIRE(hit == a.get()); + REQUIRE(cluster == a.get()); + + const auto [h, c, w] = a; + REQUIRE(h == hit); + REQUIRE(c == cluster); + REQUIRE(w == 1.0); + } +} + TEST_CASE("AssociationCollection basics", "[associations]") { auto coll = TestAColl();