Ответ 1
Это основная проблема 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)).
Почему плохо сформировалось во втором случае? Генерируемое тело лямбды создается - частично - используя предоставленные аргументы шаблона. И причиной этого частичного экземпляра является тот факт, что...
... лексические области, используемые при обработке определения функции, в корне преходящны, а это означает, что отсрочить создание некоторой части определения шаблона функции трудно.
(Richard Smith) Мы должны создать достаточный экземпляр локального "шаблона", чтобы сделать его независимым от локального контекста (который включает параметры шаблона шаблона закрывающей функции).
Это также связано с обоснованием [expr.prim.lambda]/13, в котором указывается, что объект неявно захватывается лямбдой, если он...
обозначает объект в потенциально-оцененном выражении ([basic.def.odr]), где охватывающее полное выражение зависит от общего параметра лямбда, объявленного в пределах области охвата лямбда-выражения.
То есть, если у меня есть лямбда, например [=] (auto x) {return (typename decltype(x)::type)a;}
, где a
- это какая-то переменная блока-объекта из закрывающей функции, независимо от того, является ли x
членом typedef для void
или нет, приведение будет вызвать захват a
, потому что мы должны решить это, не дожидаясь вызова lambda. Для обсуждения этой проблемы см. Оригинальное предложение для генерических лямбда.
Суть в том, что полностью откладывание экземпляра шаблона-члена несовместимо с моделью, используемой (по крайней мере одной) основной реализацией (-ами), и поскольку это ожидаемая семантика, эта функция не была введена.
Была ли это оригинальная мотивация для этого ограничения? Он был введен где-то в период с января по май 1994 года, без каких-либо документов, охватывающих его, поэтому мы можем получить только приблизительное представление о преобладающих представлениях этой статьи обоснование того, почему локальные классы не должны быть аргументами шаблона:
Шаблоны классов и классы, созданные из шаблона, являются глобальной областью и не могут ссылаться на локальные объекты сущности.
Возможно, тогда кто-то хотел KISS.