以下代码是使用VC++ 2012编译的:
void f1(void (__stdcall *)())
{}
void f2(void (__cdecl *)())
{}
void __cdecl h1()
{}
void __stdcall h2()
{}
int main()
{
f1(h1); // error C2664
f2(h2); // error C2664
f1([](){}); // OK
f2([](){}); // OK
auto fn = [](){};
f1(fn); // OK
f2(fn); // OK
}
我认为错误是正常的,但OKs是不正常的。
所以,我的问题是:
[] __stdcall (){};
[] __cdecl (){};等。
发布于 2013-02-13 11:41:54
在VC++ 2012上,当您将“无状态lambda转换为函数指针”时,编译器选择自动调用无状态lambda(没有捕获变量)的转换。
Lambdas
..。此外,在Visual Studio2012中的Visual C++中,无状态lambda可以转换为函数指针。...
编辑:
NB:调用转换不符合C++标准,它依赖于其他规范,如平台ABI(应用程序二进制接口)。
以下答案基于使用/FAs compiler option输出的汇编代码。因此,这只是一个猜测,请向微软了解更多细节;
Q1.C++λ函数的调用约定是什么?
Q3。如果没有定义调用约定,如何在调用lambda函数后正确地回收堆栈空间?
首先,lambda(-expression)不是一个函数(也不是函数指针),你可以像调用普通函数一样调用operator()
来调用C++对象。输出汇编代码表明VC++ 2012生成了带有__thiscall
调用转换的lambda-body。
Q2.如何指定C++ lambda函数的调用约定?
阿法克,没有办法。(可能只有__thiscall
)
Q4.编译器会自动生成lambda函数的多个版本吗?即下面的伪代码:...
可能不是。VC++ 2012 lambda-type只提供了一个lambda-body实现(void operator()()
),但是为每个调用转换(具有void (__fastcall*)(void)
、void (__stdcall*)(void)
和void (__cdecl*)(void)
类型的运算符返回函数指针)提供了多个“用户定义的函数指针转换”。
下面是一个例子;
// input source code
auto lm = [](){ /*lambda-body*/ };
// reversed C++ code from VC++2012 output assembly code
class lambda_UNIQUE_HASH {
void __thiscall operator()() {
/* lambda-body */
}
// user-defined conversions
typedef void (__fastcall * fp_fastcall_t)();
typedef void (__stdcall * fp_stdcall_t)();
typedef void (__cdecl * fp_cdecl_t)();
operator fp_fastcall_t() { ... }
operator fp_stdcall_t() { ... }
operator fp_cdecl_t() { ... }
};
lambda_UNIQUE_HASH lm;
发布于 2013-02-13 11:43:37
无状态的lambda函数仍然是一个类,但它是一个可以隐式转换为函数指针的类。
C++标准没有涵盖调用约定,但是在将lambda转换为函数指针时,无状态lambda不能在任何调用约定中创建包装器以转发到无状态lambda,这是没有道理的。
举个例子,我们可以这样做:
#include <iostream>
void __cdecl h1() {}
void __stdcall h2(){}
// I'm lazy:
typedef decltype(&h1) cdecl_nullary_ptr;
typedef decltype(&h2) stdcall_nullary_ptr;
template<typename StatelessNullaryFunctor>
struct make_cdecl {
static void __cdecl do_it() {
StatelessNullaryFunctor()();
}
};
template<typename StatelessNullaryFunctor>
struct make_stdcall {
static void __stdcall do_it() {
StatelessNullaryFunctor()();
}
};
struct test {
void operator()() const { hidden_implementation(); }
operator cdecl_nullary_ptr() const {
return &make_cdecl<test>::do_it;
}
operator stdcall_nullary_ptr() const {
return &make_stdcall<test>::do_it;
}
};
其中我们的test
无状态空类可以隐式地转换为cdecl
和stdcall
函数指针。
其中很重要的一点是,调用约定是函数指针类型的一部分,因此operator function_type
知道所请求的调用约定。有了完美的转发,上面的内容甚至可以是高效的。
https://stackoverflow.com/questions/14845706
复制相似问题