Почему общие лямбды разрешены, а вложенные структуры с шаблонными методами - нет?

Насколько я понимаю - родовые лямбды превращаются в объекты локального масштаба с шаблонами operator(), Это делает универсальный лямбда очень мощным и простым в использовании инструментом. С другой стороны, можно создавать структуры, вложенные в функцию, если, однако, структура имеет шаблонный член, например:

#include <iostream>

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

или сам по себе шаблон:

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

compiler seems to have a problem with compiling it:

error: invalid declaration of member template in local class

а также

error: a template declaration cannot appear at block scope

I assume the problem lays more in c++ standard than in compiler bug. What are the reasons lambdas are allowed to have templated members and not the local structures?

I found this qustion, but I think the answer is kind of outdated (I don't think it's true even for c++11).

2 ответа

Решение

Это основной вопрос 728, который был подан до того, как появились общие лямбды.

Вы упомянули общие лямбды и то, что они были идентичны локальным классам с соответствующим членом 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)).

Почему плохо сформирован во втором случае? Базовое тело лямбды создается - частично - с использованием предоставленных аргументов шаблона. И причиной этого частичного воплощения является тот факт, что...

… Лексические области действия, используемые при обработке определения функции, являются в основном временными, что означает, что задержка создания экземпляра некоторой части определения шаблона функции трудно поддерживать.

( Ричард Смит) Мы должны создать достаточно экземпляра локального "шаблона", чтобы сделать его независимым от локального контекста (который включает параметры шаблона шаблона включающей функции).

Это также связано с обоснованием для [expr.prim.lambda] / 13, который предписывает, что сущность неявно захвачена лямбда, если она…

называет сущность в потенциально вычисляемом выражении ([basic.def.odr]), где заключающее полное выражение зависит от универсального лямбда-параметра, объявленного в пределах охвата лямбда-выражения.

То есть, если у меня есть лямбда-лайк [=] (auto x) {return (typename decltype(x)::type)a;}, где a некоторая переменная области блока из функции включения, независимо от того, xТип пользователя typedef предназначен для void или нет, актерский состав вызовет захват aпотому что мы должны решить это, не дожидаясь вызова лямбды. Обсуждение этой проблемы см. В оригинальном предложении об общих лямбдах.

Суть в том, что полное откладывание создания экземпляра шаблона элемента несовместимо с моделью, используемой (по крайней мере, одной) основной (-ыми) реализацией (-ями), и, поскольку это ожидаемая семантика, функция не была представлена.


Это была первоначальная мотивация для этого ограничения? Он был введен где-то в период с января по май 1994 года, и в нем не было ни одного документа, поэтому мы можем получить лишь приблизительное представление о преобладающих понятиях из обоснования этой статьи о том, почему локальные классы не должны быть шаблонными аргументами:

Шаблоны классов и классы, сгенерированные из шаблона, являются объектами глобальной области и не могут ссылаться на объекты локальной области.

Возможно, тогда кто-то хотел поцеловать.

Я предполагаю, что проблема лежит больше в стандарте C++

Правильный. Это предусмотрено в [temp] для шаблонов классов:

Объявление шаблона может появляться только как область видимости пространства имен или декларация области класса.

и [temp.mem] для шаблонов элементов:

Локальный класс не замыкающего типа не должен иметь шаблонов членов.


По каким причинам лямбдам разрешено иметь шаблонных членов, а не местные структуры?

Поскольку после того, как у нас появились лямбды в C++11, считалось, что было бы чрезвычайно полезно расширить эту концепцию, чтобы иметь общие лямбды. Было предложение о таком расширении языка, которое было пересмотрено, пересмотрено и принято.

С другой стороны, еще не было представлено предложение (насколько я знаю из краткого поиска), в котором изложена мотивация необходимости шаблонов элементов в локальных классах, которая не может быть адекватно решена с помощью общей лямбды.,

Если вы считаете, что это важная проблема, которую необходимо решить, не стесняйтесь подавать предложение после того, как изложите продуманную мотивацию того, почему шаблоны локальных членов важны.

Другие вопросы по тегам