lambdas的可继承性是否由标准保证



在C++标准中,闭包类型定义如下:

[expr.prim.lambda.closure] lambda 表达式的类型(也是闭包的类型( object( 是唯一的、未命名的非联合类类型,称为闭包 类型,其属性如下所述。[...]

该标准似乎没有定义未命名的非联合类类型是否是最终的。将 lambda 实现为最终类的编译器是否符合标准,或者我们是否可以保证可以从 lambda 继承?

问题不在于从 lambda 继承是否有用:它是给定的,它是有用的。问题是该标准是否提供了这种保证。

是的,闭包类型不能是最终的。至少这是我的解释。

§8.1.5.1 闭包类型 [expr.prim.lambda.closure]

实现可以定义闭包类型,而不是 下面描述,前提是这不会改变可观察的行为 除更改外的程序:

  • 。[不适用]

然后,该标准不会将闭包类型描述为最终类型。使其成为最终将改变可观察的行为,因此闭包类型不能是最终的。

关于可观察的行为。考虑一下:

auto l = []{};
return std::is_final_v<decltype(l)>;

使闭包类型最终化将明显修改有效程序的可观察行为。


至于用例,它实际上可能是一个非常有用的功能:

template <class... Fs> struct Overload : Fs ...
{
    using Fs::operator()...;
};
template <class... Fs> Overload(Fs...) -> Overload<Fs...>;
auto test()
{
    Overload f = {[] (int a) { return a * 100; },
                  [] (int a, int b) { return a + b;}};
    return f(1) + f(2, 3); // 105
}

在 godbolt 上看到它的实际效果


感谢 hvd 和 rakete1111 在评论中的讨论和反馈。

final的效果在 [class]/3 中指定:

如果一个类用 class-virt-specifier final 标记,并且它在基子句中显示为 class-or-decltype,则程序格式不正确。

也就是说,课程是否是最终的并不重要。仅使用final说明符标记类才重要。由于闭包类型在源文件中没有任何声明,因此不可能将其标记为final,因此 [class]/3 不适用。

最新更新