ich einen Code haben, die Anordnung für eine JIT Idee erzeugt arbeite ich an. Ich benutze Metaprogrammierung, um Aufrufe zu generieren, indem ich den Funktionstyp analysiere und dann die richtige Assembly erzeuge, um sie aufzurufen. Ich wollte vor kurzem Lambda-Unterstützung hinzufügen, und Lambdas haben zwei Versionen, nicht erfassen (normale __cdecl Funktionsaufruf) und erfassen (__thiscall, Member-Function-Aufruf mit dem Lambda-Objekt als Kontext).erkennen, wenn C++ Lambda kann umgewandelt werden Zeiger auf Funktion
__thiscall ist etwas teurer, so würde Ich mag es zu vermeiden, wann immer möglich, und ich würde auch auf dem Lambda-Typ abhängig unterschiedliche Anruferzeugungsfunktionen zu vermeiden, wie zu verwenden.
Ich habe versucht, viele Möglichkeiten, um die Lambda-Typ über Templates und SFINAE und alle sind gescheitert zu erkennen.
Nicht erfassende Lambdas haben eine ::operator function_type*
, die man verwenden kann, um sie in Funktionszeiger umzuwandeln, während das Erfassen von Lambda dies nicht tut.
Relevante C++ Spezifikation: http://en.cppreference.com/w/cpp/language/lambda
Irgendwelche Ideen?
bearbeiten Ich mag würde, eine Lösung haben, die für vs 2013/2015 arbeitet, gcc und Klirren
Prüfregeln folgt
#include <utility>
//this doesn't work
template < class C, class T >
struct HasConversion {
static int test(decltype(std::declval<C>().operator T*, bool()) bar) {
return 1;
}
static int test(...) {
return 0;
}
};
template <class C>
void lambda_pointer(C lambda) {
int(*function)() = lambda;
printf("Lambda function: %p without context\n", function);
}
template <class C>
void lambda_pointer_ctx(C lambda) {
int(C::*function)() const = &C::operator();
void* context = λ
printf("Lambda function: %p with context: %p\n", function, context);
}
int main() {
int a;
auto l1 = [] {
return 5;
};
auto l2 = [a] {
return a;
};
//non capturing case
//works as expected
lambda_pointer(l1);
//works as expected (ctx is meaningless and not used)
lambda_pointer_ctx(l1);
//lambda with capture (needs context)
//fails as expected
lambda_pointer(l1);
//works as expected (ctx is a pointer to class containing the captures)
lambda_pointer_ctx(l1);
/*
//this doesn't work :<
typedef int afunct() const;
HasConversion<decltype(l1), afunct>::test(0);
HasConversion<decltype(l2), afunct>::test(0);
*/
return 0;
}
Kennen Sie die Unterschrift des Lambda? Das macht es ein bisschen sauberer, wenn Sie es tun. – Yakk
Wenn Sie die Signatur kannten, könnten Sie 'std :: is_assignable {}', oder in Ihrem Fall 'std :: is_assignable {} 'mit' typedef void afunct (int); ' –
Nein, das muss für jede Signatur funktionieren - ich folge dem Aufruf, der aus der Signatur generiert werden soll –