我从Unreal Engine的源中遇到了以下代码
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))
现在,每当我们使用ensure(SomeExpression)
时,UE4Asserts_Private::TrueFirstCallOnly
的{{1}}参数仅在它第一次被特定的调用堆栈调用时才为true(我认为每个调用堆栈都需要,因为FDebug::OptionallyLogFormattedEnsureMessageReturningFalse
在下一次调用时评估为false以确保来自同一调用栈的确保,但从另一个调用栈触发了sure但不是很确定),我不知道这是如何工作的。
正如他们在评论中所述,以某种方式将lambda TrueOnFirstCallOnly
传递给模板函数会对其进行唯一实例化。它是如何工作的?作为模板传递的lambda真正独特的是什么,是调用堆栈还是其他?
[]{}
为真
答案 0 :(得分:1)
这是可以实现这样的true_on_first_call
的方式:
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();
}
诀窍在于,每个labmda表达式都具有唯一的类型,因此它将导致true_on_first_call
的不同实例化。即使Lambda表达式相同([]{}
与[]{}
),它们的类型也不同。另一方面,相同的lambda表达式(即foo
的第一次调用的那个和foo
的第二次调用的那个)具有相同的类型。这样,您每次编写get_true_on_first_call([]{})
时都可以获得唯一的实例。