为什么允许使用通用 lambda,而不允许使用具有模板化方法的嵌套结构?

Why generic lambdas are allowed while nested structs with templated methods aren't?

本文关键字:方法 结构 嵌套 许使用 lambda 为什么 不允许      更新时间:2023-10-16

据我所知-泛型lambdas被转换为局部作用域结构的对象与模板化的operator()。这使得泛型lambda非常强大和易于使用的工具。另一方面,可以创建嵌套到函数中的结构体,但是该结构体具有模板化的成员,例如:

#include <iostream>
int main() {
    struct inner {
    template <class T>
       void operator()(T &&i) { }
    };
    return 0;
}

or被自己模板化:

int main() {
    template <class T>
    struct inner {
       void operator()(T &&i) { }
    };
    return 0;
}

编译器在编译它时似乎有问题:

error: invalid declaration of member template in local class

error: a template declaration cannot appear at block scope

我认为问题更多地在于c++标准而不是编译器错误。什么原因允许lambda有模板化的成员而不是局部结构?

我发现了这个问题,但我认为答案有点过时了(我不认为这是真的,即使是c++11)。

这是核心问题728,它是在泛型lambda出现之前提交的。

你提到了泛型lambda,它们与具有相应成员template operator()的局部类相同。然而,它们实际上并非如此,它们之间的差异与实现特性有关。考虑

template <typename T>
class X {
    template <typename>
    void foo() {
        T t;
    }
};

template <typename T>
auto bar() {
    return [] (auto) {T t;};
};

<void>实例化这些模板在第一种情况下是好的,但在第二种情况下是错误的。为什么第一种情况下没问题?foo不需要为每个特定的T实例化,而只需要为其中一个实例化(这将是[temp.res]/(8.1))。

为什么在第二种情况下是病态的?使用提供的模板参数来实例化泛型lambda的主体(部分地)。这个部分实例化的原因是…

处理函数定义时使用的词法作用域基本上是暂时的,这意味着很难支持延迟函数模板定义的某些部分的实例化。
我们必须实例化足够的局部"模板",使其独立于局部上下文(其中包括封闭函数模板的模板参数)。

这也与基本原理有关[expr.prim。/13,它规定如果一个实体…

在潜在求值表达式([basic.def.odr])中命名实体,其中封闭的完整表达式依赖于在lambda表达式的可达范围内声明的泛型lambda参数。

也就是说,如果我有一个像[=] (auto x) {return (typename decltype(x)::type)a;}这样的lambda,其中a是来自封闭函数的块作用域变量,不管x的成员类型是否为void,强制转换将导致捕获a,因为我们必须在不等待lambda调用的情况下决定这一点。有关此问题的讨论,请参阅泛型lambda的原始提案。

底线是,完全推迟成员模板的实例化与(至少一个)主要实现所使用的模型不兼容,并且由于这些是预期的语义,因此没有引入该特性。


这是这个约束的原始动机吗?它是在1994年1月到5月之间的某个时候被引入的,没有论文涉及它,所以我们只能从这篇论文中对为什么局部类不能作为模板参数的论证中得到一个大致的流行概念:

类模板和从模板生成的类是全局作用域实体,不能引用局部作用域实体。

也许在那个时候,一个人想要接吻。

我认为问题更多地出在c++标准

正确的。这在类模板的[temp]中有规定:

模板声明只能作为命名空间作用域或类作用域声明出现。

和[temp.mem]的成员模板:

非闭包类型的局部类不能有成员模板。


为什么lambda可以有模板化的成员而不是局部结构?

因为一旦我们在c++ 11中有了lambda,我们就认为将这个概念扩展为泛型lambda是非常有用的。有一项关于这种语言扩展的建议,经修订和修订并通过。

另一方面,目前还没有一个提案(据我从一个简短的搜索中了解到)提出了在局部类中需要成员模板的动机,而泛型lambda不能充分解决这个问题。

如果你觉得这是一个需要解决的重要问题,在提出一个深思熟虑的动机来说明为什么本地成员模板很重要之后,可以自由提交一个提案。