简体   繁体   中英

How does the following code work to uniquely instantiate a template function everytime for a unique call-stack?

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();
}

Live demo

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM