On Sun 3/15/2026 7:32 AM, Bonita Montero wrote:
If you have an API that requires a callback and you want to have that
this callback can access the outer scope like a lambda through [%]
I'm doing this:
template<typename EnumProc>
requires std::is_nothrow_invocable_r_v<BOOL, EnumProc, LPWSTR, DWORD, LPARAM>
BOOL EnumSystemLocalesEx( EnumProc enumProc, DWORD dwFlags, LPARAM
lParam, LPVOID lpReserved )
{
˙˙˙˙thread_local EnumProc *t_pCallback;
˙˙˙˙t_pCallback = &enumProc;
˙˙˙˙return EnumSystemLocalesEx( +[]( LPWSTR locName, DWORD dwFlags,
LPARAM lParam )
˙˙˙˙˙˙˙ {
˙˙˙˙˙˙˙˙˙˙˙ return (*t_pCallback)( locName, dwFlags, lParam );
˙˙˙˙˙˙˙ }, dwFlags, lParam, lpReserved );
}
With the above concept you can use these C-APIs like a C++ API.
Firstly, using a [pseudo-]global variable to pass additional context to "context-unfriendly" functions (i.e. a `static` or `thread_local`
variable) is an old and trivial technique. It is ugly, so it should be
used as a desperate last resort only. Declaring that [pseudo-]global
variable locally and "templatizing" the whole thing does not really
redeem it.
Which brings us to "secondly".
Secondly, it is not clear why you used `EnumSystemLocalesEx` in this
example. `EnumSystemLocalesEx` happens to be a context-friendly API,
which does not require one to use this workaround at all. The entire
WinAPI is designed to be context-friendly from day one. So, just use
'lParam' to pass context and achieve the same thing. Yes, it will
require a bit of an extra effort, since the client might want to pass
its own 'lParam' value, but it is not that difficult to handle nicely
and is definitely worth it
template<typename EnumProc>
requires std::is_nothrow_invocable_r_v<BOOL, EnumProc, LPWSTR,
DWORD, LPARAM>
BOOL MyEnumSystemLocalesEx(EnumProc enumProc, DWORD dwFlags, LPARAM
lParam, LPVOID lpReserved)
{
using Lpp = std::pair<EnumProc &, LPARAM>;
const Lpp lp = { enumProc, lParam };
return EnumSystemLocalesEx(+[](LPWSTR locName, DWORD dwFlags,
LPARAM lParam)
{
const Lpp *lp = (Lpp *) lParam;
return lp->first(locName, dwFlags, lp->second);
}, dwFlags, (LPARAM) &lp, lpReserved);
}
Thirdly, relying on partial ordering alone to avoid infinite recursion
is a recipe for unnecessary problems.
--
Best regards,
Andrey
--- PyGate Linux v1.5.13
* Origin: Dragon's Lair, PyGate NNTP<>Fido Gate (3:633/10)