Как можно operator()
лямбда объявляется как noreturn
?
Ideone принимает следующий код:
#include <cstdlib>
int main() {
[]() [[noreturn]] { std::exit(1); }();
return 0;
}
Clang 3.5 отклоняет это с:
error: 'noreturn' attribute cannot be applied to types
Вы можете попробовать это в Godbolt: http://goo.gl/vsuCsF
Какой из них прав?
Обновить: соответствующие стандартные разделы выглядят как 5.1.2.5, 7.6.3, 7.6.4, но после прочтения мне все еще не ясно на 100% (i) каково правильное поведение, (ii) как пометить оператора () лямбда как noreturn
,
Clang это правильно. Атрибут может относиться к объявленной функции или к ее типу; два разные. [[noreturn]]
должен относиться к самой функции. Разницу можно увидеть в
// [[noreturn]] appertains to the entity that's being declared
void f [[noreturn]] (); // §8.3 [dcl.meaning]/p1:
// The optional attribute-specifier-seq following a
// declarator-id appertains to the entity that is declared."[[noreturn]] void h (); // §7 [dcl.dcl]/p2:
// "The attribute-specifier-seq in a simple-declaration
// appertains to each of the entities declared by
// the declarators of the init-declarator-list."
// ill-formed - [[noreturn]] appertains to the type (§8.3.5 [dcl.fct]/p1:
// "The optional attribute-specifier-seq appertains to the function type.")
void g () [[noreturn]] {}
Действительно, если вы скомпилируете это в g ++, это скажет вам, что
warning: attribute ignored [-Wattributes]
void g () [[noreturn]] {}
^
note: an attribute that appertains to a type-specifier is ignored
Обратите внимание, что он не выдает предупреждение о том, что g()
на самом деле возвращается.
С «Атрибут спецификатор-сл в лямбда-описатель относится к типу соответствующего оператора вызова функции или шаблона оператора «(§5.1.2 [expr.prim.lambda] / p5), а не к самому шаблону оператора / оператора, вы не можете использовать [[noreturn]]
там. В более общем смысле язык не позволяет вам применить атрибут к operator ()
самой лямбды.
Таким образом, лямбда-делькаратор имеет следующую грамматику черновик стандартного раздела C ++ 5.1.2
Лямбда-выражения:
( parameter-declaration-clause ) mutableopt exception-specificationopt attribute-specifier-seqopt trailing-return-typeopt
и атрибут noreturn действительно является действительным Атрибут спецификатор-сл так что с точки зрения грамматики я не вижу ограничения из раздела 7.6.3
Атрибут норетурн это говорит (Акцент шахты идет вперед):
[…] Атрибут может быть применен к идентификатору объявления в функции
декларация. […]
который, по-видимому, не запрещает ваше использование, но предполагает, что это запрещено. Если мы посмотрим на раздел 7.6.4
Несет атрибут зависимости это говорит:
[…] Атрибут может быть применен к объявителю-идентификатору
объявление параметра в объявлении функции или лямбда[…]
тот факт, что он явно включает случай лямда 7.6.3
предназначен для исключения лямбд и, следовательно, clang
было бы правильно. В качестве примечания, Visual Studio также отклоняет этот код.
[C++11: 7.6.3/1]:
Атрибут-маркерnoreturn
указывает, что функция не возвращает. Это должно появиться не более одного раза в каждом список атрибутов и нет атрибут-аргумент придаточного должен присутствовать. Атрибут может быть применен к описатель-идентификатор в объявлении функции. Первое объявление функции должно указыватьnoreturn
атрибут, если любое объявление этой функции определяетnoreturn
приписывать. Если функция объявлена сnoreturn
атрибут в одной единице перевода и та же функция объявляется безnoreturn
атрибут в другой единице перевода, программа плохо сформирована; Диагностика не требуется.
Я допускаю, что эта формулировка, как она есть, не запрещает появление атрибута в другом месте, но в сочетании с отсутствием каких-либо доказательств в стандарте для него, я не думаю, что это предназначено для работы с лямбда-декларациями.
Поэтому Clang будет прав.
Это может или не может говорить, что было предложение патча к Clang, чтобы позволить стиль GCC noreturn
атрибуты на лямбдах, но не стандартная форма.
К сожалению, эта функция не включена в Список расширений GCC, так что я не могу точно увидеть, что здесь происходит.