gpt4 book ai didi

c++ - 检测 C++ lambda 是否可以转换为函数指针

转载 作者:可可西里 更新时间:2023-11-01 16:36:49 27 4
gpt4 key购买 nike

我有一些代码可以为我正在处理的 JIT 想法生成程序集。我使用元编程通过分析函数类型来生成调用,然后生成正确的程序集来调用它。我最近想添加 lambda 支持,lambda 有两个版本,非捕获(正常的 __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 = &lambda;

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特点:

auto lambda = [] (char, double) -> int { return 0; };
using signature = int(char, double);
static_assert(std::is_assignable<signature*&, decltype(lambda)>::value, "!");

DEMO

这样它也可以与通用 lambda 一起工作。


I'd like to have a solution that works for vs 2013/2015, gcc and clang

如果您不知道签名,这里有一种方法可以替代检查 + 是否触发隐式转换。这个利用了 std::is_assignable 测试并验证 lambda 是否可分配给与 lambda 的函数调用运算符具有相同签名的函数指针。 (就像使用一元运算符 plus 的测试一样,这不适用于通用 lambda。但在 C++11 中没有通用 lambda)。

#include <type_traits>

template <typename T>
struct identity { using type = T; };

template <typename...>
using void_t = void;

template <typename F>
struct call_operator;

template <typename C, typename R, typename... A>
struct call_operator<R(C::*)(A...)> : identity<R(A...)> {};

template <typename C, typename R, typename... A>
struct call_operator<R(C::*)(A...) const> : identity<R(A...)> {};

template <typename F>
using call_operator_t = typename call_operator<F>::type;

template <typename, typename = void_t<>>
struct is_convertible_to_function
: std::false_type {};

template <typename L>
struct is_convertible_to_function<L, void_t<decltype(&L::operator())>>
: std::is_assignable<call_operator_t<decltype(&L::operator())>*&, L> {};

测试:

int main()
{
auto x = [] { return 5; };
auto y = [x] { return x(); };

static_assert(is_convertible_to_function<decltype(x)>::value, "!");
static_assert(!is_convertible_to_function<decltype(y)>::value, "!");
}

GCC , VC++ , Clang++

关于c++ - 检测 C++ lambda 是否可以转换为函数指针,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32025355/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com