简体   繁体   English

为什么 lambda 函数的每个实例化都会产生唯一的类型?

[英]Why does each instantiation of a lambda function result in a unique type?

Recently I asked a question about some code I had which was causing my compiler to run out of heap space.最近我问了一个关于我的一些代码的问题,这些代码导致我的编译器耗尽了堆空间。 This code contained a recursive template function which was being passed a lambda function.此代码包含一个递归模板函数,该函数被传递给一个 lambda 函数。 Each instantiation of the template function caused (via the recursive call) another instantiation of the same template function with it's lambda function parameter.模板函数的每个实例化都导致(通过递归调用)使用它的 lambda 函数参数对同一模板函数进行另一个实例化。 It was explained that each instantiation of the lambda function results in a unique type, so an infinite loop of instantiations results and the compiler runs out of heap.有人解释说,lambda 函数的每个实例化都会产生一个唯一的类型,因此会导致实例化的无限循环,并且编译器会耗尽堆。 Note that the logic of the program is such that there would be no infinite loop at runtime.请注意,程序的逻辑是在运行时不会出现无限循环。

Here's an example of the code, this code does not compile on any of the major compilers.这是代码示例,此代码无法在任何主要编译器上编译。 This code is a heavily cut down version of my real code, it's just for illustrative purposes.这段代码是我真实代码的大幅缩减版本,仅用于说明目的。

struct Null
{
    template <typename SK>
    static int match(int n, SK sk)
    {
        return 0;
    }
};

template <typename T>
struct Repetition
{
    template <typename SK>
    static int match(int n, SK sk)
    {
        return T::match(0, [n]() { return match(0, [n](){ return n; }); });
    }
};

int main()
{
    using Test = Repetition<Null>;
    Test::match(0, [](){ return 0; });
}

When this was explained it occurred to me that I could break the infinite loop by using a functor instead of a lambda function, since each instantiation of a the functor would not be a unique type.当解释这一点时,我突然想到我可以通过使用仿函数而不是 lambda 函数来打破无限循环,因为仿函数的每个实例化都不是唯一的类型。 Here's that code, this compiles fine这是代码,编译得很好

struct Null
{
    template <typename SK>
    static int match(int n, SK sk)
    {
        return 0;
    }
};

template <typename T>
struct Repetition
{
    template <typename SK>
    static int match(int n, SK sk)
    {
        return T::match(0, [n]() { return match(0, RepetitionSK<T>(n)); });
    }
};

template <typename T>
struct RepetitionSK
{
    RepetitionSK(int n) : n(n) {}
    int operator()() { return n; }
    int n;
};

int main()
{
    using Test = Repetition<Null>;
    Test::match(0, [](){ return 0; });
}

EDIT [=] captures have been replaced by the more explicit [n] EDIT [=] 捕获已被更明确的 [n] 取代

My question is that why do lambda functions behave this way?我的问题是,为什么 lambda 函数会这样? The lambda functions in Repetition::match do not depend the template parameter SK in any way. Repetition::match中的 lambda 函数不以任何方式依赖模板参数SK What's the benefit in having each instantiation of a lambda function result in a unique type?让 lambda 函数的每个实例化都产生唯一类型有什么好处?

Another question, is it possible to write this code using only lambda functions, no functors or other auxiliary classes?另一个问题,是否可以仅使用 lambda 函数而不使用仿函数或其他辅助类来编写此代码?

The question is more easily answered by considering the opposite.通过考虑相反的情况,这个问题更容易回答。 If it were not true, then some lambda's would have the same type.如果它不是真的,那么一些 lambda 将具有相同的类型。 Furthermore, the Standard should then say which lambda's have the same type, and which lambda's have distinct types.此外,标准应该说明哪些 lambda 具有相同的类型,哪些 lambda 具有不同的类型。

Note that with "type" we mean more than just the signature of operator() .请注意,“类型”不仅仅意味着operator()的签名。 Lambda's have real type, eg they've got a sizeof (which has to include the captured state). Lambda 有真实的类型,例如它们有一个sizeof (必须包括捕获的状态)。

For that reason, you can't just define the type in terms of tokens;出于这个原因,您不能只根据标记来定义类型; the token T may be the same but the meaning varies across instantiations.令牌T可能相同,但含义因实例而异。

This idea isn't entirely unique;这个想法并不完全是独一无二的。 non-inline functions are also unique even if they contain the exact same tokens (but then the function type will be the same - the correspondence isn't exact. And functions don't have a sizeof )非内联函数也是唯一的,即使它们包含完全相同的标记(但函数类型将相同 - 对应关系不准确。并且函数没有sizeof

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 模板与lambda作为每个实例化的唯一默认参数 - template with lambda as unique default parameter on each instantiation 为每个模板实例化生成唯一的类型或ID? (示例观察者模式) - Generate a unique type or id for each template instantiation? ( example observer pattern ) 为什么将 lambda 传递给受约束的类型模板参数会导致“不完整类型”编译器错误? - Why does passing lambda to constrained type template parameter result in `incomplete type` compiler error? 编译器是否为每个lambda生成不同的类型? - Does the compiler generate a different type for each lambda? 为什么 = default 成员初始值设定项请求实例化 unique_ptr 析构函数而 {} 不? - Why does = default member initializer request instantiation of unique_ptr destructor while {} does not? 为什么在模板实例化中不允许使用lambda? - Why isn't a lambda allowed in a template instantiation? 为什么unique_ptr实例化编译为比原始指针更大的二进制? - Why does unique_ptr instantiation compile to larger binary than raw pointer? 获取模板函数/通用lambda的唯一返回类型 - get unique return type of template function/generic lambda std :: function type和template instantiation - std::function type and template instantiation 为什么lambda init-capture不能用于unique_ptr? - Why does lambda init-capture not work for unique_ptr?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM