【问题标题】:How does the following code work to uniquely instantiate a template function everytime for a unique call-stack?以下代码如何每次都为唯一的调用堆栈唯一地实例化模板函数?
【发布时间】:2018-09-21 18:14:29
【问题描述】:

我从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) 时,FDebug::OptionallyLogFormattedEnsureMessageReturningFalseUE4Asserts_Private::TrueFirstCallOnly 参数仅在它第一次被特定调用堆栈调用时才计算为真(我正在考虑每个调用堆栈,因为 TrueOnFirstCallOnly 计算为在下一次调用时为 false 以确保来自同一个调用堆栈,但会从不同的调用堆栈触发确保,但不是很确定),我不明白这是如何工作的。

正如他们在 cmets 中所说,不知何故将 lambda []{} 传递给模板函数会唯一地实例化它。它是如何工作的?作为模板传递的 lambda 真正独特的是什么,是调用堆栈还是其他什么?

LIKELY(!!(InExpression)) 如果表达式为真,则可以认为其计算结果为真

【问题讨论】:

    标签: c++ templates lambda


    【解决方案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();
    }
    

    Live demo

    诀窍在于每个 labmda 表达式都有一个唯一的类型,因此它将导致 true_on_first_call 的不同实例化。即使 lambda 表达式相同([]{}[]{}),它们的类型也不同。另一方面,相同的 lambda 表达式(即第一次调用foo 和第二次调用foo 的表达式)属于同一类型。这样,您每次编写get_true_on_first_call([]{}) 时都可以获得唯一的实例化。

    【讨论】:

      猜你喜欢
      • 2016-04-07
      • 1970-01-01
      • 2017-07-18
      • 2019-06-21
      • 2022-11-22
      • 2014-12-07
      • 2021-06-20
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多