Почему общие лямбды разрешены, а вложенные структуры с шаблонными методами - нет?
Насколько я понимаю - родовые лямбды превращаются в объекты локального масштаба с шаблонами 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, считалось, что было бы чрезвычайно полезно расширить эту концепцию, чтобы иметь общие лямбды. Было предложение о таком расширении языка, которое было пересмотрено, пересмотрено и принято.
С другой стороны, еще не было представлено предложение (насколько я знаю из краткого поиска), в котором изложена мотивация необходимости шаблонов элементов в локальных классах, которая не может быть адекватно решена с помощью общей лямбды.,
Если вы считаете, что это важная проблема, которую необходимо решить, не стесняйтесь подавать предложение после того, как изложите продуманную мотивацию того, почему шаблоны локальных членов важны.