Metaprogramming: detect structured types
This solution checks only the minimal precondition, which is that a type supports `std::tuple_size<T>`. A more complete implementation turns out to be surprisingly complex, since a direct check likely requires compile-time reflection capabilities at the level of at least C++23 - `std::tuple_element<i,T>` typically implements limits checks, which interfere with the detection of empty structured types - the situation regarding `std::get<i>()` is even more complicated, since we might have to probe for ADL-based solutions, or member templates The check for minimal necessary precondition however allows us to single out std::tuple, std::array and our own structured types in compilation branching, which suffices to fulfils actual needs.
This commit is contained in:
parent
03b17c78da
commit
23b4a54e79
4 changed files with 131 additions and 18 deletions
|
|
@ -189,6 +189,34 @@ namespace meta {
|
|||
|
||||
|
||||
|
||||
namespace {
|
||||
/**
|
||||
* check for the necessary precondition, not sufficient.
|
||||
* @remark Detecting the possibility of structured binding reliably will be possible with C++23.
|
||||
* Even a partial implementation, covering only `std::tuple_element` is surprisingly
|
||||
* complicated, due to the built-in limit checks. What do do with a `tuple<>`?
|
||||
*/
|
||||
template<class TUP, size_t siz =std::tuple_size<TUP>::value>
|
||||
struct _Probe_TupleProtocol
|
||||
{ };
|
||||
}
|
||||
template<class TUP>
|
||||
using enable_if_TupleProtocol = std::void_t<_Probe_TupleProtocol<std::decay_t<TUP>>>;
|
||||
|
||||
/** Trait template to detect a »tuple-like« type,
|
||||
* which can be used in structured bindings.
|
||||
* @note we check only one precondition: the support for `std::tuple_size`
|
||||
*/
|
||||
template<class X, typename =void>
|
||||
struct is_Structured
|
||||
: std::false_type
|
||||
{ };
|
||||
|
||||
template<class TUP>
|
||||
struct is_Structured<TUP, enable_if_TupleProtocol<TUP>>
|
||||
: std::true_type
|
||||
{ };
|
||||
|
||||
|
||||
/** Trait template for detecting a typelist type.
|
||||
* For example, this allows to write specialisations
|
||||
|
|
|
|||
|
|
@ -107,23 +107,19 @@ namespace engine {
|
|||
using lib::meta::is_TernaryFun;
|
||||
using std::remove_reference_t;
|
||||
using lib::meta::enable_if;
|
||||
using lib::meta::is_Structured;
|
||||
using std::is_pointer;
|
||||
using std::is_reference;
|
||||
using std::tuple_size_v;
|
||||
using std::void_t;
|
||||
using std::__and_;
|
||||
using std::__not_;
|
||||
|
||||
template<class X, typename SEL=void>
|
||||
struct is_Structured
|
||||
: std::false_type
|
||||
{ };
|
||||
template<class TUP>
|
||||
struct is_Structured<TUP, void_t<std::tuple_size<TUP>>>
|
||||
: std::true_type
|
||||
{ };
|
||||
|
||||
template<typename V>
|
||||
struct is_Value
|
||||
: __and_<__not_<std::is_pointer<V>>
|
||||
,__not_<std::is_reference<V>>
|
||||
: __and_<__not_<is_pointer<V>>
|
||||
,__not_<is_reference<V>>
|
||||
,__not_<is_Structured<V>>
|
||||
,std::is_default_constructible<V>
|
||||
,std::is_copy_assignable<V>
|
||||
|
|
@ -132,13 +128,17 @@ namespace engine {
|
|||
|
||||
template<typename B>
|
||||
struct is_Buffer
|
||||
: __and_<__not_<std::is_pointer<B>>
|
||||
,__not_<std::is_reference<B>>
|
||||
: __and_<__not_<is_pointer<B>>
|
||||
,__not_<is_reference<B>>
|
||||
,std::is_default_constructible<B>
|
||||
,__not_<_Fun<B>>
|
||||
>
|
||||
{ };
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/** Helper to pick up the parameter dimensions from the processing function
|
||||
* @remark this is the rather simple yet common case that media processing
|
||||
* is done by a function, which takes an array of input and output
|
||||
|
|
|
|||
|
|
@ -20,20 +20,21 @@
|
|||
#include "lib/test/run.hpp"
|
||||
#include "lib/meta/util.hpp"
|
||||
#include "lib/meta/typelist.hpp"
|
||||
#include "lib/hetero-data.hpp"
|
||||
#include "lib/test/diagnostic-output.hpp"
|
||||
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
using std::cout;
|
||||
using std::endl;/////////////////////////TODO
|
||||
|
||||
#include <array>
|
||||
#include <tuple>
|
||||
|
||||
namespace lib {
|
||||
namespace meta {
|
||||
namespace test {
|
||||
|
||||
using std::string;
|
||||
|
||||
|
||||
using std::array;
|
||||
using std::tuple;
|
||||
using std::pair;
|
||||
|
||||
|
||||
|
||||
|
|
@ -42,6 +43,7 @@ namespace test {
|
|||
* @test verify basic type trait and metaprogramming helpers.
|
||||
* - marker types to tell which overload the compiler picks
|
||||
* - simple trait to detect the possibility of a string conversion
|
||||
* - trait to detect (possibly) structured types (»tuple-like«)
|
||||
* - trait to detect a typelist type
|
||||
*/
|
||||
class MetaUtils_test : public Test
|
||||
|
|
@ -53,6 +55,7 @@ namespace test {
|
|||
verify_genericTypeDisplay();
|
||||
|
||||
detect_stringConversion();
|
||||
detect_tupleProtocol();
|
||||
detect_typeList();
|
||||
}
|
||||
|
||||
|
|
@ -162,6 +165,42 @@ namespace test {
|
|||
}
|
||||
|
||||
|
||||
void
|
||||
detect_tupleProtocol()
|
||||
{
|
||||
// verify arbitrary non-structured types
|
||||
CHECK ((not is_Structured<void >()));
|
||||
CHECK ((not is_Structured<void* >()));
|
||||
CHECK ((not is_Structured<const void* >()));
|
||||
CHECK ((not is_Structured<const int >()));
|
||||
CHECK ((not is_Structured<int >()));
|
||||
CHECK ((not is_Structured<int & >()));
|
||||
CHECK ((not is_Structured<int const & >()));
|
||||
CHECK ((not is_Structured<int const * >()));
|
||||
CHECK ((not is_Structured<int * >()));
|
||||
CHECK ((not is_Structured<int * const >()));
|
||||
CHECK ((not is_Structured<int * const & >()));
|
||||
CHECK ((not is_Structured<int * & >()));
|
||||
CHECK ((not is_Structured<int * && >()));
|
||||
CHECK ((not is_Structured<int && >()));
|
||||
CHECK ((not is_Structured<int const && >()));
|
||||
CHECK ((not is_Structured<double >()));
|
||||
CHECK ((not is_Structured<string >()));
|
||||
CHECK ((not is_Structured<Node<short,NullType> >()));
|
||||
|
||||
// the following indeed support C++ tuple protocol
|
||||
CHECK (( is_Structured<tuple<int> >()));
|
||||
CHECK (( is_Structured<tuple<int,char,long> >()));
|
||||
CHECK (( is_Structured<tuple<> >()));
|
||||
CHECK (( is_Structured<pair<short,long> >()));
|
||||
CHECK (( is_Structured<array<short,5> >()));
|
||||
CHECK (( is_Structured<array<long,0> >()));
|
||||
CHECK (( is_Structured<HeteroData<size_t> >()));
|
||||
CHECK (( is_Structured<HeteroData<int,char> >()));
|
||||
CHECK (( is_Structured<HeteroData<> >()));
|
||||
}
|
||||
|
||||
|
||||
|
||||
//-------------------------------------------------TEST-types--
|
||||
typedef Types< int
|
||||
|
|
|
|||
|
|
@ -92049,6 +92049,52 @@ Date:   Thu Apr 20 18:53:17 2023 +0200<br/>
|
|||
</node>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1734300380799" ID="ID_782708625" MODIFIED="1734300402299" TEXT="dann die Erweiterung auf strukturierte Typen dazunehmen">
|
||||
<icon BUILTIN="flag-yellow"/>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1734397892641" ID="ID_23248062" MODIFIED="1734397907072" TEXT="praktisch-technisch mühsam...">
|
||||
<icon BUILTIN="flag-yellow"/>
|
||||
<node CREATED="1734397915749" ID="ID_1226245371" MODIFIED="1734397929207" TEXT="muß Prädikate auf alle Typen anwenden"/>
|
||||
<node CREATED="1734397930454" ID="ID_1067248557" MODIFIED="1734397961120" TEXT="brauche Operation über Elemente eines strukturierten Typs"/>
|
||||
<node CREATED="1734403556414" ID="ID_971023481" MODIFIED="1734403580870" TEXT="muß dazu den Einzelfall-Typ auf einen structured-Type »heben«">
|
||||
<node CREATED="1734403583091" ID="ID_1710377001" MODIFIED="1734403593253" TEXT="StructType<TY>">
|
||||
<node COLOR="#435e98" CREATED="1734403595048" ID="ID_496079267" MODIFIED="1734450365546" TEXT="spricht falsch an im Compile">
|
||||
<icon BUILTIN="broken-line"/>
|
||||
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#a6086b" CREATED="1734403634332" ID="ID_817342705" MODIFIED="1734450390281" TEXT="funktioniert enable_if<is_Structured<long*> > korrekt?"/>
|
||||
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#690f14" CREATED="1734450087903" ID="ID_1588306692" MODIFIED="1734450379412" TEXT="is_Structured war naiv implementiert">
|
||||
<icon BUILTIN="broken-line"/>
|
||||
</node>
|
||||
<node COLOR="#338800" CREATED="1734450102857" ID="ID_1962318483" MODIFIED="1734450109137" TEXT="versuche es besser...">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
<node COLOR="#5b280f" CREATED="1734450111282" ID="ID_1778075632" MODIFIED="1734450135378" TEXT="das ganze »tuple-protocol« abprüfen">
|
||||
<icon BUILTIN="button_cancel"/>
|
||||
<node CREATED="1734450137253" ID="ID_1390904069" MODIFIED="1734450144643" TEXT="unverhältnismäßig aufwendig"/>
|
||||
<node CREATED="1734450146232" ID="ID_1193364290" MODIFIED="1734450167735" TEXT="ein Problem sind die size-Limits, die bei leeren Tuples ansprechen"/>
|
||||
<node CREATED="1734450169097" ID="ID_1451956704" MODIFIED="1734450194401" TEXT="und für std::get gäbe es diverse Varianten (siehe die Probleme mit lib::HeteroData)"/>
|
||||
</node>
|
||||
<node COLOR="#435e98" CREATED="1734450197246" ID="ID_1518898869" MODIFIED="1734450228376" TEXT="die notwendige Bedingung: muß std::tuple_size<T> unterstützen">
|
||||
<icon BUILTIN="yes"/>
|
||||
</node>
|
||||
<node COLOR="#338800" CREATED="1734450249909" ID="ID_1798931733" MODIFIED="1734450323184" TEXT="extrahiert nach lib/meta/util.hpp">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
<node COLOR="#435e98" CREATED="1734450269831" ID="ID_1495231260" MODIFIED="1734450319900" TEXT="sauber formuliert mit separatem Probe-Template"/>
|
||||
<node COLOR="#435e98" CREATED="1734450281377" ID="ID_258396157" MODIFIED="1734450319901" TEXT="ein enable_if-Variante dazu"/>
|
||||
<node COLOR="#435e98" CREATED="1734450289604" ID="ID_1035452314" MODIFIED="1734450357273" TEXT="getestet mit verschiedenen Typen">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<p>
|
||||
MetaUtils_test::detect_tupleProtocol()
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1734133400400" ID="ID_1364724277" MODIFIED="1734141875620" TEXT="zusätzlichen Funktor für die Parameter akzeptieren">
|
||||
|
|
|
|||
Loading…
Reference in a new issue