From 2533565f836cbe8707b76821427596e8b9c3979a Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Fri, 24 Nov 2017 01:21:03 +0100 Subject: [PATCH] Research: probing a generic lambda is not possible ...since all those metaprogramming techniques rely on SFINAE, but *instantiating* a template means to compile it, which is more than just substituate a type into the signature If forming the signature fails -> SFINAE, try next one If instantiating a template fails -> compile error, abort --- research/try.cpp | 92 ++++++++++++++++++++++++++++------------ wiki/thinkPad.ichthyo.mm | 69 ++++++++++++++++++++++++++++++ 2 files changed, 133 insertions(+), 28 deletions(-) diff --git a/research/try.cpp b/research/try.cpp index cf4dbbed4..5660841eb 100644 --- a/research/try.cpp +++ b/research/try.cpp @@ -39,6 +39,9 @@ /** @file try.cpp ** Metaprogramming: is it possible to distinguish a generic lambda from something not a function at all? + ** Answer: not really. We can only ever check for the function call operator. + ** Even worse: if we instantiate a templated function call operator with unsuitable parameter types, + ** the compilation as such fails. Whereas SFINAE is only limited to substituting a type signature. */ typedef unsigned int uint; @@ -54,6 +57,7 @@ typedef unsigned int uint; using lib::meta::No_t; using lib::meta::Yes_t; +using lib::meta::_Fun; using lib::test::showSizeof; using std::function; @@ -62,6 +66,58 @@ using std::move; using std::string; +namespace lib { +namespace meta{ + + + template + struct ProbeFunctionInvocation + { + using Ret = decltype(std::declval() (std::declval()...)); + using Args = Types; + using Sig = Ret(ARGS...); + }; + + template + class can_Invoke + { + template() (std::declval()...))> + struct Probe + { }; + + template + static Yes_t check(Probe * ); + template + static No_t check(...); + + public: + static const bool value = (sizeof(Yes_t)==sizeof(check(0))); + }; + + + template + struct ProbeFunctionArgument + { + static_assert(not sizeof(FUN), "Tilt"); + }; + + template + struct ProbeFunctionArgument, enable_if> > + : ProbeFunctionInvocation + { }; + + template + struct ProbeFunctionArgument, disable_if> > + : ProbeFunctionArgument + { + + }; +}} + +using lib::meta::Types; +using lib::meta::can_Invoke; +using lib::meta::ProbeFunctionArgument; #define SHOW_TYPE(_TY_) \ @@ -70,34 +126,6 @@ using std::string; cout << "Probe " << STRINGIFY(_XX_) << " ? = " << _XX_ <::value)); + SHOW_EXPR ((can_Invoke::value )); + + using InferredSIG = typename ProbeFunctionArgument::List>::Sig; + //NOTE does not work with the generic lamb2, because instantiating lab2(string) would be a *compile* error, not a substitution failure + + SHOW_TYPE (InferredSIG); + cout << "\n.gulp.\n"; return 0; diff --git a/wiki/thinkPad.ichthyo.mm b/wiki/thinkPad.ichthyo.mm index 2c84efa8d..3f2d32eb5 100644 --- a/wiki/thinkPad.ichthyo.mm +++ b/wiki/thinkPad.ichthyo.mm @@ -5238,6 +5238,9 @@ + + + @@ -5247,6 +5250,72 @@ + + + + + + + + + +

+ aber eine falsche Template-Instantiierung +

+

+ ist ein Compile-Fehler, kein Substitutions-Fehler +

+ + +
+
+
+
+
+ + + + + + + + + + + +

+ oder man fällt auf eine mögliche Substitution zurück +

+ + +
+
+ + + + + + +

+ ...und wenn die Scheitert, ist das ein compile-Fehler +

+ + +
+
+
+ + + + + + +

+ denn das ist der sinnvollste Fall für ein generisches Lambda +

+ + +