Является ли наследование лямбда гарантированным стандартом?

В стандарте C++ типы закрытия определяются следующим образом:

[expr.prim.lambda.closure] Тип лямбда-выражения (который также является типом объекта замыкания) - это уникальный, неназванный тип неединичного класса, называемый типом замыкания, свойства которого описаны ниже. [...]

Стандарт, по-видимому, не определяет, является ли неопределенный тип неединичного класса окончательным. Будет ли компилятор, реализующий lambdas в качестве окончательных классов, соответствовать стандарту, или у нас есть гарантия, что можно наследовать от лямбда?

Вопрос не в том, полезен он или нет для наследования у лямбда: это то, что оно полезно. Вопрос в том, обеспечивает ли стандарт эту гарантию.

Ответ 1

Да, тип закрытия не должен быть окончательным. По крайней мере, это моя интерпретация.

§8.1.5.1 Типы закрытия [expr.prim.lambda.closure]

Реализация может определять тип закрытия иначе, чем описано ниже, если это не изменяет наблюдаемое поведение программы, кроме как путем изменения:

  • ... [не применяется]

Стандарт тогда не описывает тип закрытия как окончательный. Создание окончательного варианта изменило бы наблюдаемое поведение ergo, тип закрытия не должен быть окончательным.

Что касается наблюдаемого поведения. Учти это:

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 для обсуждений и отзывов в комментариях.

Ответ 2

Эффект final указан в [class]/3:

Если класс помечается final спецификатором class-virt-specifier и он выглядит как класс-или-decltype в базовом условии, программа плохо сформирована.

То есть, не имеет значения, является ли класс окончательным. Это имеет значение только для маркировки класса final спецификатором. Так как тип замыкания не имеет никакого объявления в исходном файле, невозможно пометить его как final, и, следовательно, [class]/3 не применяется.