虽然有很多关于获取任何模板化回调函数/方法(当然包括 lambdas)的返回类型的东西,但我很难找到有关解决 lambda 函数的完整调用签名的信息。至少在 gcc 4.7 中,它似乎是正常技巧(见下文)不起作用的边缘情况。这是我目前正在尝试做的事情(当然是精简版)......
template<typename Sig>
struct invokable_type { };
template<typename R, typename...As>
struct invokable_type<R(As...)> {
static constexpr size_t n = sizeof...(As);
typedef R(callable_type)(As...);
template<size_t i>
struct arg {
typedef typename peel_type<i, As...> type;
};
};
peel_type<size_t, typename...>
为简洁起见,此处不包括在内,但它是一个简单的参数类型剥离器(我认为 C++11 内置了一个,但我从不费心去看)。这个问题不重要。
然后,当然,对于无数可调用类型(例如R(*)(As...)
, R(&)(As...)
, (R(T::*)(As...)
, std::function<R(As...)>
, 方法 cv 限定符、方法左值/右值限定符等)存在专门化(以及进一步的属性/类型定义)。
然后,在某个地方,我们有一个可爱的函数或方法(这里的函数,没关系),看起来像......
template<typename C, typename...As>
static void do_something(C&& callback, As&&...as) {
do_something_handler<invokable_type<C>::n, As...>::something(std::forward<C>(callback), std::forward<As>(as)...);
}
没关系do_something_handler
……这完全无关紧要。问题在于 lambda 函数。
对于我专门针对的所有可能的通用可调用签名(似乎都是非 STL 仿函数),当do_something()
将它们作为第一个参数调用时,这可以很好地工作(模板推导完全有效)。但是,lambda 函数会导致未捕获的类型签名,从而导致被使用,这意味着类似的invokable_type<Sig>
东西根本不存在。::n
::args<0>::type
没问题的例子...
void something(int x, int y) {
return x * y;
}
... 然后...
do_something(something, 7, 23);
问题示例...
do_something([](int x, int y) {
return x * y;
}, 7, 23);
如果我正确理解 lambda 函数,编译器很可能会将此 lambda 编译为定义范围的“命名空间”内的静态函数(gcc 似乎确实如此)。对于我的生活,我无法弄清楚签名实际上是什么。看起来它肯定有一个可以通过模板专业化(基于错误报告)来推断的。
另一个切题的问题是,即使有一个我可以使用的签名,这个交叉编译器有多危险?lambda 编译签名是标准化的还是全面的?