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
This commit is contained in:
parent
01937f9736
commit
2533565f83
2 changed files with 133 additions and 28 deletions
|
|
@ -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<class FUN, typename...ARGS>
|
||||
struct ProbeFunctionInvocation
|
||||
{
|
||||
using Ret = decltype(std::declval<FUN>() (std::declval<ARGS>()...));
|
||||
using Args = Types<ARGS...>;
|
||||
using Sig = Ret(ARGS...);
|
||||
};
|
||||
|
||||
template<typename FUN, typename...ARGS>
|
||||
class can_Invoke
|
||||
{
|
||||
template<typename FF,
|
||||
typename SEL = decltype(std::declval<FF>() (std::declval<ARGS>()...))>
|
||||
struct Probe
|
||||
{ };
|
||||
|
||||
template<class X>
|
||||
static Yes_t check(Probe<X> * );
|
||||
template<class>
|
||||
static No_t check(...);
|
||||
|
||||
public:
|
||||
static const bool value = (sizeof(Yes_t)==sizeof(check<FUN>(0)));
|
||||
};
|
||||
|
||||
|
||||
template<class FUN, typename TYPES, typename SEL =void>
|
||||
struct ProbeFunctionArgument
|
||||
{
|
||||
static_assert(not sizeof(FUN), "Tilt");
|
||||
};
|
||||
|
||||
template<class FUN, typename T, typename TYPES>
|
||||
struct ProbeFunctionArgument<FUN, Node<T,TYPES>, enable_if<can_Invoke<FUN,T>> >
|
||||
: ProbeFunctionInvocation<FUN,T>
|
||||
{ };
|
||||
|
||||
template<class FUN, typename T, typename TYPES>
|
||||
struct ProbeFunctionArgument<FUN, Node<T,TYPES>, disable_if<can_Invoke<FUN,T>> >
|
||||
: ProbeFunctionArgument<FUN, TYPES>
|
||||
{
|
||||
|
||||
};
|
||||
}}
|
||||
|
||||
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_ <<endl;
|
||||
|
||||
|
||||
void
|
||||
fun1 (long)
|
||||
{
|
||||
cout << "long FUN" <<endl;
|
||||
}
|
||||
|
||||
int
|
||||
fun1 (string, long)
|
||||
{
|
||||
cout << "string FUN" <<endl;
|
||||
return 12;
|
||||
}
|
||||
|
||||
void
|
||||
fun1 ()
|
||||
{
|
||||
cout << "NO FUN" <<endl;
|
||||
}
|
||||
|
||||
|
||||
class Cheesy
|
||||
{ };
|
||||
|
||||
class Fishy
|
||||
{
|
||||
friend void fun1 (Fishy&);
|
||||
};
|
||||
|
||||
|
||||
int
|
||||
main (int, char**)
|
||||
|
|
@ -108,6 +136,14 @@ main (int, char**)
|
|||
SHOW_TYPE (decltype(lamb1));
|
||||
SHOW_TYPE (decltype(lamb2));
|
||||
|
||||
SHOW_EXPR ((can_Invoke<decltype(lamb1), string>::value));
|
||||
SHOW_EXPR ((can_Invoke<decltype(lamb2), int>::value ));
|
||||
|
||||
using InferredSIG = typename ProbeFunctionArgument<decltype(lamb1), typename Types<string,long,int>::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;
|
||||
|
|
|
|||
|
|
@ -5238,6 +5238,9 @@
|
|||
<icon BUILTIN="pencil"/>
|
||||
<node CREATED="1511455644829" ID="ID_1545300823" MODIFIED="1511455655796" TEXT="ist generisches Labmda detektierbar?">
|
||||
<icon BUILTIN="help"/>
|
||||
<node CREATED="1511482195487" ID="ID_954120351" MODIFIED="1511482198474" TEXT="jein"/>
|
||||
<node CREATED="1511482200510" ID="ID_714363558" MODIFIED="1511482216359" TEXT="man kann nur einen Funktionsoperator erkennen"/>
|
||||
<node CREATED="1511482216971" ID="ID_1806534330" MODIFIED="1511482240548" TEXT="nicht aber, wenn ein Solcher mehrere Overloads hat oder ein Template ist"/>
|
||||
</node>
|
||||
<node CREATED="1511455664043" ID="ID_1966980711" MODIFIED="1511455676078" TEXT="kann man Fallback-Mechanismus bauen?">
|
||||
<icon BUILTIN="help"/>
|
||||
|
|
@ -5247,6 +5250,72 @@
|
|||
<node CREATED="1511455711525" ID="ID_1584168712" MODIFIED="1511455721127" TEXT="(a) mit dem Value-Type ins Argument"/>
|
||||
<node CREATED="1511455721907" ID="ID_312038081" MODIFIED="1511455730558" TEXT="(b) mit dem Iterator-Typ ins Argument"/>
|
||||
</node>
|
||||
<node CREATED="1511482247535" ID="ID_487969118" MODIFIED="1511482309885" TEXT="geht nicht">
|
||||
<icon BUILTIN="broken-line"/>
|
||||
<node CREATED="1511482254927" ID="ID_1687625403" MODIFIED="1511482263673" TEXT="zwar funktionieren die Positiv-Fälle"/>
|
||||
<node CREATED="1511482264405" ID="ID_1003171577" MODIFIED="1511482304307">
|
||||
<richcontent TYPE="NODE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<p>
|
||||
aber eine falsche Template-Instantiierung
|
||||
</p>
|
||||
<p>
|
||||
ist ein <i>Compile</i>-Fehler, kein <i>Substitutions</i>-Fehler
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1511482367184" ID="ID_1569720883" MODIFIED="1511482519599" TEXT="bleibt nur...">
|
||||
<icon BUILTIN="pencil"/>
|
||||
<node CREATED="1511482374415" ID="ID_554184880" MODIFIED="1511482441927" TEXT="maximal ein Versuch">
|
||||
<icon BUILTIN="yes"/>
|
||||
<node CREATED="1511482446317" ID="ID_951810826" MODIFIED="1511482457247" TEXT="entweder der Typ der Funktion ist bestimmbar"/>
|
||||
<node CREATED="1511482457978" ID="ID_564239157" MODIFIED="1511482493455">
|
||||
<richcontent TYPE="NODE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<p>
|
||||
oder man fällt auf <i>eine</i> mögliche Substitution zurück
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
</node>
|
||||
<node CREATED="1511482495719" ID="ID_327135583" MODIFIED="1511482510962">
|
||||
<richcontent TYPE="NODE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<p>
|
||||
...und wenn die Scheitert, ist das ein <b>compile</b>-Fehler
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
</node>
|
||||
</node>
|
||||
<node CREATED="1511482393172" ID="ID_1538766965" MODIFIED="1511482428415" TEXT="das wäre dann: den Iterator zu verwenden">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<p>
|
||||
denn das ist der sinnvollste Fall für ein generisches Lambda
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
|
|
|
|||
Loading…
Reference in a new issue