diff --git a/extern/typed-geometry b/extern/typed-geometry
index 7aa50e07ec78dc6a24c11222d17ed325dae94e55..b2642eb7a1630106a71bf50e46ba6599830e226b 160000
--- a/extern/typed-geometry
+++ b/extern/typed-geometry
@@ -1 +1 @@
-Subproject commit 7aa50e07ec78dc6a24c11222d17ed325dae94e55
+Subproject commit b2642eb7a1630106a71bf50e46ba6599830e226b
diff --git a/tests/impl-report.cc b/tests/impl-report.cc
index ee0a1fd17884b5e788bd27c85c1cfd65da467ad7..06ef44a1f020c0a09e46ca6b5528e7aa635c3779 100644
--- a/tests/impl-report.cc
+++ b/tests/impl-report.cc
@@ -11,21 +11,6 @@
 
 namespace
 {
-// see https://stackoverflow.com/questions/44395169/why-is-sfinae-on-if-constexpr-not-allowed
-namespace detail
-{
-template <template <class...> class, class, class...>
-struct can_apply : std::false_type
-{
-};
-template <template <class...> class Z, class... Ts>
-struct can_apply<Z, std::void_t<Z<Ts...>>, Ts...> : std::true_type
-{
-};
-[[maybe_unused]] tg::rng rng;
-}
-template <template <class...> class Z, class... Ts>
-constexpr bool can_apply = detail::can_apply<Z, void, Ts...>::value;
 
 template <class T>
 using try_print = decltype(std::declval<std::ostream&>() << std::declval<T>());
@@ -55,7 +40,7 @@ template <class T>
 using try_contains_pos3 = decltype(contains(std::declval<T const&>(), tg::pos3()));
 
 template <class T>
-using try_uniform = decltype(uniform(detail::rng, std::declval<T const&>()));
+using try_uniform = decltype(uniform(std::declval<tg::rng>(), std::declval<T const&>()));
 
 template <class T>
 using try_aabb_of = decltype(aabb_of(std::declval<T const&>()));
@@ -96,7 +81,7 @@ void test_single_object_type(std::string name)
     static auto constexpr domainD = tg::object_traits<ObjT>::domain_dimension;
     static auto constexpr objectD = tg::object_traits<ObjT>::object_dimension;
     static auto constexpr solidD = [] {
-        if constexpr (can_apply<try_solid_of, ObjT>)
+        if constexpr (tg::can_apply<try_solid_of, ObjT>)
             return tg::object_traits<try_solid_of<ObjT>>::object_dimension;
         return objectD;
     }(); // ternary constexpr of solid domain with fallback to object domain
@@ -104,7 +89,7 @@ void test_single_object_type(std::string name)
     if constexpr (!std::is_default_constructible_v<ObjT>)
         std::cerr << "cannot default construct tg::" << name << std::endl;
 
-    if constexpr (can_apply<try_print, ObjT>)
+    if constexpr (tg::can_apply<try_print, ObjT>)
     {
         std::stringstream ss;
         ss << ObjT{};
@@ -118,39 +103,39 @@ void test_single_object_type(std::string name)
     else
         std::cerr << "cannot print tg::" << name << std::endl;
 
-    if constexpr (!can_apply<try_equal, ObjT>)
+    if constexpr (!tg::can_apply<try_equal, ObjT>)
         std::cerr << "equality not implemented for tg::" << name << std::endl;
 
     // TODO: somehow doesnt work?
-    if constexpr (!can_apply<try_less, ObjT>)
+    if constexpr (!tg::can_apply<try_less, ObjT>)
         std::cerr << "std::less not specialized for tg::" << name << std::endl;
 
-    if constexpr (!can_apply<try_hash, ObjT>)
+    if constexpr (!tg::can_apply<try_hash, ObjT>)
         std::cerr << "std::hash not specialized for tg::" << name << std::endl;
 
-    if constexpr (!can_apply<try_any_point, ObjT>)
+    if constexpr (!tg::can_apply<try_any_point, ObjT>)
         std::cerr << "no any_point(tg::" << name << ")" << std::endl;
 
     if constexpr (domainD == 2)
     {
-        if constexpr (!can_apply<try_project_pos2, ObjT>)
+        if constexpr (!tg::can_apply<try_project_pos2, ObjT>)
         {
             if (!(name.size() >= 7 && std::string_view(name).substr(0, 7) == "ellipse")) // project(ellipse) is not planned
                 std::cerr << "no project(tg::pos2, tg::" << name << ")" << std::endl;
         }
 
-        if constexpr (!can_apply<try_contains_pos2, ObjT>)
+        if constexpr (!tg::can_apply<try_contains_pos2, ObjT>)
             std::cerr << "no contains(tg::" << name << ", tg::pos2)" << std::endl;
     }
     else if constexpr (domainD == 3)
     {
-        if constexpr (!can_apply<try_project_pos3, ObjT>)
+        if constexpr (!tg::can_apply<try_project_pos3, ObjT>)
         {
             if (!(name.size() >= 7 && std::string_view(name).substr(0, 7) == "ellipse")) // project(ellipse) is not planned
                 std::cerr << "no project(tg::pos3, tg::" << name << ")" << std::endl;
         }
 
-        if constexpr (!can_apply<try_contains_pos3, ObjT>)
+        if constexpr (!tg::can_apply<try_contains_pos3, ObjT>)
             std::cerr << "no contains(tg::" << name << ", tg::pos3)" << std::endl;
     }
     else
@@ -159,37 +144,37 @@ void test_single_object_type(std::string name)
     // operations for finite objects
     if constexpr (tg::object_traits<ObjT>::is_finite)
     {
-        if constexpr (!can_apply<try_uniform, ObjT>)
+        if constexpr (!tg::can_apply<try_uniform, ObjT>)
             std::cerr << "no uniform(tg::rng, tg::" << name << ")" << std::endl;
 
-        if constexpr (!can_apply<try_aabb_of, ObjT>)
+        if constexpr (!tg::can_apply<try_aabb_of, ObjT>)
             std::cerr << "no aabb_of(tg::" << name << ")" << std::endl;
 
-        if constexpr (!can_apply<try_centroid_of, ObjT>)
+        if constexpr (!tg::can_apply<try_centroid_of, ObjT>)
             std::cerr << "no centroid_of(tg::" << name << ")" << std::endl;
 
         if constexpr (objectD == 1)
         {
-            if constexpr (solidD == 1 && !can_apply<try_length_of, ObjT>)
+            if constexpr (solidD == 1 && !tg::can_apply<try_length_of, ObjT>)
                 std::cerr << "no length(tg::" << name << ")" << std::endl;
 
-            if constexpr (solidD != 1 && !can_apply<try_perimeter_of, ObjT>)
+            if constexpr (solidD != 1 && !tg::can_apply<try_perimeter_of, ObjT>)
                 std::cerr << "no perimeter_of(tg::" << name << ")" << std::endl;
         }
         else if constexpr (objectD == 2)
         {
-            if constexpr (!can_apply<try_area_of, ObjT>)
+            if constexpr (!tg::can_apply<try_area_of, ObjT>)
                 std::cerr << "no area_of(tg::" << name << ")" << std::endl;
 
-            if constexpr (solidD == 2 && !can_apply<try_perimeter_of, ObjT>)
+            if constexpr (solidD == 2 && !tg::can_apply<try_perimeter_of, ObjT>)
                 std::cerr << "no perimeter_of(tg::" << name << ")" << std::endl;
         }
         else if constexpr (objectD == 3)
         {
-            if constexpr (!can_apply<try_volume_of, ObjT>)
+            if constexpr (!tg::can_apply<try_volume_of, ObjT>)
                 std::cerr << "no volume_of(tg::" << name << ")" << std::endl;
 
-            if constexpr (solidD == 3 && !can_apply<try_area_of, ObjT>)
+            if constexpr (solidD == 3 && !tg::can_apply<try_area_of, ObjT>)
                 std::cerr << "no area_of(tg::" << name << ")" << std::endl;
         }
         else
@@ -199,14 +184,14 @@ void test_single_object_type(std::string name)
     // ray intersections
     if constexpr (objectD >= domainD - 1)
     {
-        if constexpr (domainD == 2 && !can_apply<try_closest_ray2_intersect_of, ObjT>)
+        if constexpr (domainD == 2 && !tg::can_apply<try_closest_ray2_intersect_of, ObjT>)
             std::cerr << "no closest_intersection_parameter(tg::ray2, tg::" << name << ")" << std::endl;
-        if constexpr (domainD == 3 && !can_apply<try_closest_ray3_intersect_of, ObjT>)
+        if constexpr (domainD == 3 && !tg::can_apply<try_closest_ray3_intersect_of, ObjT>)
             std::cerr << "no closest_intersection_parameter(tg::ray3, tg::" << name << ")" << std::endl;
 
-        if constexpr (domainD == 2 && !can_apply<try_intersects_aabb2_of, ObjT>)
+        if constexpr (domainD == 2 && !tg::can_apply<try_intersects_aabb2_of, ObjT>)
             std::cerr << "no intersects(tg::" << name << ", tg::aabb2)" << std::endl;
-        if constexpr (domainD == 3 && !can_apply<try_intersects_aabb3_of, ObjT>)
+        if constexpr (domainD == 3 && !tg::can_apply<try_intersects_aabb3_of, ObjT>)
             std::cerr << "no intersects(tg::" << name << ", tg::aabb3)" << std::endl;
 
         // TODO: more