how to specify vc11 lambda calling convention
Cast it:
WinApiFunc(static_cast<void(__stdcall *)()>(func));
Or store it into a local variable first:
void (__stdcall *funcp)() = func;
WinApiFunc(funcp);
What's the default calling convention of a C++ lambda function?
On VC++ 2012, compiler choose automatically calling conversion for stateless lambdas (that has no capture variables) when you convert "stateless lambda to function pointer".
MSDN C++11 Features:
Lambdas
[...] Additionally in Visual C++ in Visual Studio 2012, stateless lambdas are convertible to function pointers. [...] (The Visual C++ in Visual Studio 2012 is even better than that, because we've made stateless lambdas convertible to function pointers that have arbitrary calling conventions. This is important when you are using APIs that expect things like
__stdcall
function pointers.)
EDITED:
NB: The calling conversion is out of C++ Standard, it depends on other specification such as platform ABI(application binary interface).
The following answers are based on output assembly code with /FAs compiler option.
So it's a mere guess, and please ask Microsoft for more detail ;P
Q1. What's the calling convention of a C++ lambda function?
Q3. If the calling convention is not defined, how to correctly recycle the stack space after having called a lambda function?
First of all, C++ lambda(-expression) is NOT a function (nor function pointer), you can call operator()
to lambda object like a calling normal function.
And output assembly code says that VC++ 2012 generates lambda-body with __thiscall
calling conversion.
Q2. How to specify the calling convention of a C++ lambda function?
AFAIK, there is no way. (It may be only __thiscall
)
Q4. Does the compiler automatically generate multiple versions of a lambda function? i.e. as the following pseudo-code: [...]
Probably No.
The VC++ 2012 lambda-type provides only one lambda-body implementation (void operator()()
), but provides multiple "user-defined conversion to function pointer" for each calling conversion (operator return function pointer with void (__fastcall*)(void)
, void (__stdcall*)(void)
, and void (__cdecl*)(void)
type).
Here is an example;
// 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;
Hot to handle c++11 lambda with both this pointer captured and calling convention specified
Only lambdas that do not capture anything can be converted to function pointers and this API only accepts pointers.
What you can do is to keep the lambda stateless, and transfer this
through lparam
:
EnumWindows(
[](HWND, LPARAM lparam){
return reinterpret_cast<Your_Class*>(lparam)->my_class_member_function();
},
reinterpret_cast<LPARAM>(this));
how to use __stdcall to qualify C++ lambda?
I just noticed you have the visual studio 2010
tag. Stateless lambdas were implemented in VC11. Reference:
After lambdas were voted into the Working Paper (v0.9) and mutable
lambdas were added (v1.0), the Standardization Committee overhauled
the wording, producing lambdas v1.1. This happened too late for us
to implement in VC10, but we've already implemented it in VC11. The
lambdas v1.1 wording clarifies what should happen in corner cases like
referring to static members, or nested lambdas. This fixes a bunch of
bugs triggered by complicated lambdas. Additionally, stateless
lambdas are now convertible to function pointers in VC11. This isn't
in N2927's wording, but I count it as part of lambdas v1.1 anyways.
It's FDIS 5.1.2 [expr.prim.lambda]/6: "The closure type for a
lambda-expression with no lambda-capture has a public non-virtual
non-explicit const conversion function to pointer to function having
the same parameter and return types as the closure type’s function
call operator. The value returned by this conversion function shall be
the address of a function that, when invoked, has the same effect as
invoking the closure type’s function call operator." (It's even
better than that, since we've made stateless lambdas convertible to
function pointers with arbitrary calling conventions. This is
important when dealing with APIs that expect __stdcall function
pointers and so forth.)
Also, note that this conversion happens when there is no capture specification as mentioned in the second bolded quote.
Changing Calling Convention
You can make a wrapper for translation between different calling conventions:
template<typename Func, Func* callback>
auto make_callback()
{
return &detail::callback_maker<Func, callback>::call;
}
with callback_maker
defined as
template<typename T, T*>
struct callback_maker;
template<typename R, typename... Params, R(*Func)(Params...)>
struct callback_maker<R(Params...), Func>
{
static R __stdcall call(Params... ps)
{
return Func(std::forward<Params>(ps)...);
}
};
This is aimed to be a fairly general solution, allowing you to specify the function prototype. You can use it as follows:
// external_api(¬_stdcall_func); // error
external_api(make_callback<void(int,int), ¬_stdcall_func>());
demo
If the pointer is to be determined at runtime, you could keep the callback in the user data. You'd have to manage the lifetime of that correctly, but it's likely that you already need to to that. Again, attempting a generic solution. Make a callback and tell it which argument is the user data pointer:
template<typename Callback, size_t N>
auto make_callback()
{
using callback_maker = detail::callback_maker<Callback, N>;
return &callback_maker::call;
}
With callback_maker
defined as
template<typename T, size_t N>
struct callback_maker;
template<typename R, typename... Params, size_t N>
struct callback_maker<R(*)(Params...), N>
{
using function_type = R(Params...);
static R __stdcall call(Params... ps)
{
void const* userData = get_nth_element<N>(ps...);
auto p = static_cast<pair<function_type*, void*> const*>(userData);
return p->first(ps...);
}
};
and get_nth_element
as
template<size_t N, typename First, typename... Ts>
decltype(auto) get_nth_element_impl(false_type, First&& f, Ts&&...);
template<size_t N, typename First, typename... Ts>
decltype(auto) get_nth_element_impl(true_type, First&&, Ts&&... ts)
{
return get_nth_element_impl<N-1>(integral_constant<bool, (N > 1)>{}, forward<Ts>(ts)...);
}
template<size_t N, typename First, typename... Ts>
decltype(auto) get_nth_element_impl(false_type, First&& f, Ts&&...)
{
return forward<First>(f);
}
template<size_t N, typename... Ts>
decltype(auto) get_nth_element(Ts&&... ts)
{
return get_nth_element_impl<N>(integral_constant<bool, (N > 0)>{}, forward<Ts>(ts)...);
}
Now, on the call site
using callback_t = CTMuint(*)(const void *aBuf, CTMuint aCount, void *aUserData);
auto runtime_ptr = ¬_stdcall_func;
pair<callback_t, void*> data;
data.first = runtime_ptr;
data.second = nullptr; // actual user data you wanted
auto callback = make_callback<callback_t, 2>();
ctmSaveCustom({}, callback, &data, nullptr);
demo
As per Andrey Turkin's suggestion, you can replace the user data pointer in the parameter list. Along with forward_as_tuple
, it obviates the need for get_nth_element
. The upgraded call function:
static R __stdcall call(Params... ps)
{
auto params_tuple = forward_as_tuple(ps...);
void const* userData = get<N>(params_tuple);
auto p = static_cast<pair<function_type*, void*> const*>(userData);
get<N>(params_tuple) = p->second;
return apply(p->first, move(params_tuple));
}
and here's a simplistic implementation of C++17's apply
:
template<typename Func, typename T, size_t... Is>
decltype(auto) apply_impl(Func f, T&& t, index_sequence<Is...>)
{
return f(get<Is>(t)...);
}
template<typename Func, typename... Ts>
decltype(auto) apply(Func f, tuple<Ts...>&& tup)
{
return apply_impl(f, move(tup), index_sequence_for<Ts...>{});
}
demo
Creating thread with _beginthreadex, __stdcall and a lambda
This actually almost works as-is. Lambdas with no captures can convert to function pointers so they are, to a degree, compatible with C-like APIs.
However, _beginthreadex
is expecting a function pointer to a __stdcall
function; the "native" function pointer is this; the converted lambda is not.
But Microsoft have kindly made it so that it can be! All you need is a cast to "coerce" the function pointer. This is a little unintuitive because your lambda is already __stdcall
(that's what WINAPI
expands to), but whatever.
So:
auto lambda = [](void* data) WINAPI -> unsigned int
{
return (napolniDrevo() ? 0 : 1);
};
HANDLE m_hThread = (HANDLE)_beginthreadex(
0, 0,
static_cast<unsigned int(WINAPI*)(void*)>(lambda),
0, 0, 0
);
But actually I'd recommend std::thread
instead for clean, portable code!
Nested lambda expressions are very slow to compile and generate huge object file by Visual C++
Not sure how useful such deeply nested lambdas are but for what it is worth as far as I can tell this is a bug, the Visual Studio compiler limits document states (emphasis mine):
The C++ standard recommends limits for various language constructs. The following is a list of constructs where the Visual C++ compiler does not implement the recommended limits. The first number is the recommended limit and the second number is the limit implemented by Visual C++:
and includes the following bullet:
Nesting levels of compound statements, iteration control structures, and selection control structures [256] (256).
If we look at the grammar in the C++ draft standard compound-statement will eventually get back to primary-expression which includes lambda-expression. So Visual Studio should support up to 256
levels of nesting.
You could also see this by looking at the grammar for lambda-expression which is as follows:
lambda-introducer lambda-declaratoropt compound-statement
The draft standard has a set of recommend limits in Annex B but they are only guidelines and do not determine compliance.
Update
The bug report the OP filed was updated recently to indicate this will be fixed in a future release.
Related Topics
Std::Optional - Construct Empty with {} or Std::Nullopt
Constexpr Not Working If the Function Is Declared Inside Class Scope
Visual Studio Debugger Error: Unable to Start Program Specified File Cannot Be Found
Differencebetween Wmain and Main
What Is the Purpose of Max_Digits10 and How Is It Different from Digits10
Boost::Spirit How to Parse and Call C++ Function-Like Expressions
Extra Leading Zeros When Printing Float Using Printf
How Is Floating Point Conversion Actually Done in C++(Double to Float or Float to Double)
Eclipse Mingw C++ Cannot Find -Lpthread
Why Does Stack<Const String> Not Compile in G++
What Is the Practical Use of Pointers to Member Functions
C++ -- How to Overload Operator+=
Static Variable Initialization Over a Library
Where Ampersand "&" Can Be Put When Passing Argument by Reference