From 0cad2dacc0d823827b65e31b0c8022715fac0bf3 Mon Sep 17 00:00:00 2001
From: Ichthyostega
Date: Mon, 17 Feb 2025 18:36:23 +0100
Subject: [PATCH] Invocation: build a solution to adapt `std::array`
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
...which should ''basically work,'' since `std::array` is ''»tuple-like«'' —
BUT unfortunately it has a quite distinct template signature which does not fit
into the generic scheme of a product type.
Obviously we'd need a partial specialisation, but even re-implementing this
turns out to be damn hard, because there is no way to generate a builder method
with a suitable explicit type signature directly, because such a builder would
need to accept precisely N arguments of same type. This leads to a different
solution approach: we can introduce an ''adapter type'', which will be layered
on top of `std::array` and just expose the proper type signature so that the
existing Implementation can handle the array, relying on the tuple-protocol.
__Note__: this changeset adds a convenient pretty-printer for `std::array`,
based on the same forward-declaration trick employed recently for `lib::Several`.
You need to include 'lib/format-util.hpp' to actually use it.
---
src/lib/format-obj.hpp | 8 +-
src/lib/format-util.hpp | 13 +++
src/lib/meta/tuple-closure.hpp | 89 ++++++++++++++-
tests/library/meta/tuple-closure-test.cpp | 20 ++++
wiki/thinkPad.ichthyo.mm | 127 ++++++++++++++++++++--
5 files changed, 245 insertions(+), 12 deletions(-)
diff --git a/src/lib/format-obj.hpp b/src/lib/format-obj.hpp
index b59342c63..dc5f98aa4 100644
--- a/src/lib/format-obj.hpp
+++ b/src/lib/format-obj.hpp
@@ -15,12 +15,12 @@
/** @file format-obj.hpp
** Simple functions to represent objects, for debugging and diagnostics.
** The helpers provided here are rather commonplace, but written in a way
- ** as to incur only modest header inclusion load. It should be OK to use
- ** these even on widely used interface headers.
+ ** to incur only modest header inclusion load. It should be OK to use them
+ ** even on interface headers in widespread use.
** - util::toString() performs a failsafe to-String conversion, thereby preferring a
** built-in conversion operator, falling back to a lexical conversion (boost)
- ** or just a unmangled and simplified type string as default.
- ** - util::typedString() combines this with a always visible type display
+ ** or just an unmangled and simplified type string as default.
+ ** - util::typedString() combines this with an always visible type display
** - lib::meta::demangleCxx() uses the built-in compiler support to translate a mangled
** type-ID (as given by `typeid(TY).name()`) into a readable, fully qualified
** C++ type name. This is only supported for GNU compatible compilers.
diff --git a/src/lib/format-util.hpp b/src/lib/format-util.hpp
index 1f0fd8bf8..f3b0a5cca 100644
--- a/src/lib/format-util.hpp
+++ b/src/lib/format-util.hpp
@@ -35,6 +35,7 @@
#include "lib/symbol.hpp"
#include "lib/util.hpp"
+#include
#include
#include
#include
@@ -257,6 +258,18 @@ namespace util {
{
return "["+join (forward (coll))+"]";
}
+
+
+ /** convenient pretty-printer for std::array instances */
+ template
+ struct StringConv>
+ {
+ static std::string
+ invoke (std::array const& arr) noexcept
+ {
+ return util::toStringBracket (arr);
+ }
+ };
} // namespace util
diff --git a/src/lib/meta/tuple-closure.hpp b/src/lib/meta/tuple-closure.hpp
index b77d5fa02..a0fba6cb1 100644
--- a/src/lib/meta/tuple-closure.hpp
+++ b/src/lib/meta/tuple-closure.hpp
@@ -42,6 +42,7 @@
#include
#include
+#include
@@ -96,5 +97,91 @@ namespace meta{
};
+ /* ===== adapt array for tuple-like signature ===== */
+
+ template
+ struct ArrayAdapt;
+
+ namespace {
+
+ template
+ struct AllSame
+ : std::true_type
+ { };
+
+ template
+ struct AllSame
+ : __and_
+ ,AllSame
+ >
+ { };
+
+
+ template
+ struct Repeat
+ {
+ using Rem = typename Repeat::Seq;
+ using Seq = typename Prepend::Seq;
+ };
+
+ template
+ struct Repeat
+ {
+ using Seq = TySeq<>;
+ };
+
+ template
+ struct _Adapt
+ {
+ using NFold = typename Repeat::Seq;
+ using Array = typename RebindVariadic::Type;
+ };
+
+ template
+ using _AdaptArray_t = typename _Adapt::Array;
+ }
+
+ template
+ struct ArrayAdapt
+ : std::array
+ {
+ static_assert (AllSame()
+ ,"Array can only hold elements of uniform type");
+ using Array = std::array;
+
+ ArrayAdapt (Array const& o) : Array{o} { }
+ ArrayAdapt (Array && r) : Array{move(r)} { }
+
+ template
+ ArrayAdapt (XS&& ...inits)
+ : Array{std::forward (inits)...}
+ { }
+ };
+
+ template
+ struct TupleClosureBuilder>
+ : TupleClosureBuilder<_AdaptArray_t>
+ {
+ };
+
+
}} // namespace lib::meta
-#endif
+
+
+namespace std { // Specialisation to support C++ »Tuple Protocol« and structured bindings.
+
+ /** determine compile-time fixed size of the adapted std::array */
+ template
+ struct tuple_size >
+ : integral_constant
+ { };
+
+ /** expose the element type of the adapted std::array */
+ template
+ struct tuple_element >
+ : tuple_element::Array>
+ { };
+
+ // Note: the std::get function will pick the subclass
+}
+#endif /*LIB_META_TUPLE_CLOSURE_H*/
diff --git a/tests/library/meta/tuple-closure-test.cpp b/tests/library/meta/tuple-closure-test.cpp
index 8afc7327b..2db0d019c 100644
--- a/tests/library/meta/tuple-closure-test.cpp
+++ b/tests/library/meta/tuple-closure-test.cpp
@@ -24,6 +24,7 @@
#include "lib/test/run.hpp"
#include "lib/test/test-helper.hpp"
#include "lib/meta/tuple-closure.hpp"
+#include "lib/format-util.hpp"
#include "lib/test/diagnostic-output.hpp"////////////////TODO
@@ -35,6 +36,7 @@ namespace test {
using std::string;
using std::tuple;
+ using std::array;
using std::make_tuple;
using lib::meta::_Fun;
using lib::test::showType;
@@ -53,6 +55,7 @@ namespace test {
{
tuple_bindFront();
tuple_bindBack();
+ array_bindFront();
}
@@ -94,6 +97,23 @@ SHOW_EXPR(showType())
Tup t2 = c2(make_tuple (-1));
CHECK (t2 == "«tuple»──(-1,3.1415927,pi)"_expect);
}
+
+
+ /** @test use a std::array and handle it like a tuple to pre-fix some elements
+ */
+ void
+ array_bindFront()
+ {
+ using Arr = array;
+ using Builder = TupleClosureBuilder;
+
+ auto cons = Builder::closeFront (1u,2.3);
+ using FunType = _Fun;
+ CHECK (showType() == "ArrayAdapt (ArrayAdapt)"_expect);
+
+ Arr arr = cons({3,4,5});
+ CHECK (arr == "[1, 2, 3, 4, 5]"_expect);
+ }
};
diff --git a/wiki/thinkPad.ichthyo.mm b/wiki/thinkPad.ichthyo.mm
index f95f556da..d6a231fb0 100644
--- a/wiki/thinkPad.ichthyo.mm
+++ b/wiki/thinkPad.ichthyo.mm
@@ -91202,11 +91202,9 @@ Date: Thu Apr 20 18:53:17 2023 +0200
-
+
+
-
-
-
@@ -106029,6 +106027,39 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension)
+
+
+
+
+
+
+
+
+
+
+
+
+ BuildFunSig
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -154188,7 +154219,7 @@ std::cout << tmpl.render({"what", "World"}) << s
Einschränkungen aufrufbar, aber diesen Umstand kann man nur ausnützen, solange das Lambda keine captures hat; denn andernfalls wird es ein wirkliches Objekt mit Storage und Lebenszyklus.
- Gefährlich wird es aber, wenn man auf den Umkehrschluß aufbaut, mit der Annahme, eine bool-konvertierbare Funktion sei deaktivierbar. Also wenn man dieser Flag eine zusätzliche Bedeutung zuweist
+ Gefährlich wird es aber, wenn man auf den Umkehrschluß aufbaut, mit der Annahme, eine bool-konvertierbare Funktion sei deaktivierbar. Also wenn man dieser Flag eine zusätzliche Bedeutung zuweist