Как работает следующий код, чтобы каждый раз создавать уникальные экземпляры шаблонной функции для уникального стека вызовов? - PullRequest
0 голосов
/ 21 сентября 2018

Я встречал следующий код из 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 для FDebug::OptionallyLogFormattedEnsureMessageReturningFalse оцениваетсяЗначение true только в первый раз, когда его вызывают для определенного стека вызовов (я думаю, для каждого стека вызовов, поскольку TrueOnFirstCallOnly оценивает значение false при следующем вызове, чтобы убедиться из того же стека вызовов, но вызывает гарантию из другого стека вызовов, но неочень уверен) и я не понимаю, как это работает.

Как говорится в комментариях, каким-то образом передача лямбды []{} в функцию шаблона уникальным образом создает ее экземпляр.Как это работает?И для чего лямбда, переданная в качестве шаблона, действительно уникальна, это стек вызовов или что-то еще?

LIKELY(!!(InExpression)) можно просто оценить как истинное, если выражение истинно

1 Ответ

0 голосов
/ 21 сентября 2018

Вот как можно реализовать такой 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();
}

Live demo

Хитрость в том, что каждое выражение labmda имеет уникальный тип,следовательно, это приведет к иному созданию true_on_first_call.Даже если лямбда-выражения одинаковы ([]{} против []{}), они имеют различный тип.С другой стороны, одно и то же лямбда-выражение (т. Е. Одно при первом вызове foo и одно при втором вызове foo) относятся к одному типу.Таким образом, каждый раз, когда вы пишете get_true_on_first_call([]{}).

, вы можете получать уникальные экземпляры.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...