I've encountered the following code from Unreal Engine 's source
namespace UE4Asserts_Private
{
// This is used by ensure to generate a bool per instance
// by passing a lambda which will uniquely instantiate the template.
template <typename Type>
bool TrueOnFirstCallOnly(const Type&)
{
static bool bValue = true;
bool Result = bValue;
bValue = false;
return Result;
}
FORCEINLINE bool OptionallyDebugBreakAndPromptForRemoteReturningFalse(bool bBreak, bool bIsEnsure = false)
{
if (bBreak)
{
FPlatformMisc::DebugBreakAndPromptForRemoteReturningFalse(bIsEnsure);
}
return false;
}
}
#define ensure( InExpression ) (LIKELY(!!(InExpression)) || FDebug::OptionallyLogFormattedEnsureMessageReturningFalse(UE4Asserts_Private::TrueOnFirstCallOnly([]{}), #InExpression, __FILE__, __LINE__, TEXT("") ) || UE4Asserts_Private::OptionallyDebugBreakAndPromptForRemoteReturningFalse(UE4Asserts_Private::TrueOnFirstCallOnly([]{}), true))
Now, whenever we use ensure(SomeExpression)
, the UE4Asserts_Private::TrueFirstCallOnly
argument to FDebug::OptionallyLogFormattedEnsureMessageReturningFalse
evaluates to true only on the first time it gets called for a particular callstack ( I'm thinking per callstack, as TrueOnFirstCallOnly
evaluates to false on the next call to ensure from the same callstack, but triggers the ensure from a different callstack but not very sure ) and I don't understand how this works.
As they state in the comments, Somehow passing the lambda []{}
to the template function uniquely instantiates it. How does it work? And what is the lambda passed as a template really unique for, is it the call-stack or something else?
LIKELY(!!(InExpression))
can be just thought to evaluate to true if the expression is true
This is how such a true_on_first_call
could be implemented:
include <iostream>
template <typename T> struct true_on_first_call {
static bool first;
bool operator()() {
if (first) {
first = false;
return true;
}
return false;
}
};
template <typename T> bool true_on_first_call<T>::first = true;
template <typename T>
bool get_true_on_first_call(const T &){ return true_on_first_call<T>()(); }
void foo() {
std::cout << get_true_on_first_call([]{}) << "\n"; // instantiation for []{}
}
void bar() {
std::cout << get_true_on_first_call([]{}) << "\n"; // instantiation for []{}
} // note: its a different type
// than the []{} above!
// but the same on
// repeated calls to foo
int main() {
std::cout << "first \n";
foo();
bar();
std::cout << "second \n";
foo();
bar();
}
The trick is that each labmda expression has a unique type, hence it will result in a different instantiation of true_on_first_call
. Even if the lambdas expressions are the same ( []{}
vs []{}
) they are of different type. On the other hand, the same lambda expression (ie the one on first call of foo
and the one on second call of foo
) are of same type. In this way one can get a unique instantiation each time you write get_true_on_first_call([]{})
.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.