【发布时间】:2015-11-08 14:41:58
【问题描述】:
我有一些代码可以为我正在研究的 JIT 想法生成程序集。我使用元编程通过分析函数类型来生成调用,然后生成正确的程序集来调用它。我最近想添加 lambda 支持,而 lambdas 有两个版本,非捕获(普通 __cdecl 函数调用)和捕获(__thiscall,以 lambda 对象为上下文的成员函数调用)。
__thiscall 稍微贵一些,所以我想尽可能避免使用它,并且我还想避免必须根据 lambda 类型使用不同的调用生成函数。
我尝试了很多方法来通过模板和 SFINAE 检测 lambda 类型,但都失败了。
非捕获 lambda 有一个 ::operator function_type* 可以用来将它们转换为函数指针,而捕获 lambda 则没有。
相关 C++ 规范:http://en.cppreference.com/w/cpp/language/lambda
有什么想法吗?
编辑 我想要一个适用于 vs 2013/2015、gcc 和 clang 的解决方案
测试代码如下
#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;
}
【问题讨论】:
-
你知道 lambda 的签名吗?如果你这样做,它会更干净一些。
-
如果你知道签名,你可以利用
std::is_assignable<void(*&)(int), decltype(lambda)>{},或者,在你的情况下,std::is_assignable<afunct*&, decltype(lambda)>{}和typedef void afunct(int); -
不,这对任何签名都有效——我推断要从签名生成调用
-
这很有趣,我确实推断出 lambda 的签名,它适用于所有情况
-
在测试了目前为止的所有解决方案后,这是唯一适用于 vs2013 && 2015 的解决方案!试图看看我是否可以将它弯曲成通用的:D
标签: c++ templates c++11 lambda template-meta-programming