Подтвердить что ты не робот

Как объявить lambda operator() как noreturn?

Как можно объявить 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.

4b9b3361

Ответ 1

Кланг верен. Атрибут может указывать на объявляемую функцию или на ее тип; они разные. [[noreturn]] должен принадлежать самой функции. Разницу можно увидеть в

// [[noreturn]] appertains to the entity that 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() действительно возвращается.

Поскольку "атрибут-спецификатор-seq в лямбда-деклараторе относится к типу соответствующего оператора вызова функции или шаблону оператора" (§5.1.2 [expr.prim.lambda]/p5), а не к этому оператору/сам оператор, вы не можете использовать [[noreturn]] там. В более общем плане язык не дает вам возможности применить атрибут к operator () самой лямбда.

Ответ 2

Таким образом, лямбда-делькаратор имеет следующую грамматику в стандартном разделе проекта С++ 5.1.2 Лямбда-выражения:

( parameter-declaration-clause ) mutableopt exception-specificationopt attribute-specifier-seqopt trailing-return-typeopt

и атрибут noreturn действительно является допустимым атрибутом-спецификатором-seq, поэтому с точки зрения грамматики я не вижу ограничения из раздела 7.6.3 Атрибут Noreturn, который он говорит (акцент мой вперед):

[...] Атрибут может быть применен к идентификатору declarator в функции декларация. [...]

который, кажется, не запрещает ваше использование, но он предполагает, что он не разрешен. Если мы посмотрим на раздел 7.6.4 Задает атрибут зависимости, он говорит:

[...] Атрибут может быть применен к идентификатору-декларатору Объявление параметра в объявлении функции или лямбда [...]

тот факт, что он явно включает в себя ламповый случай, сильно указывает на то, что раздел 7.6.3 предназначен для исключения лямбда и, следовательно, clang будет правильным. В качестве дополнительной заметки Visual Studio также отклоняет этот код.

Ответ 3

[C++11: 7.6.3/1]: Атрибут-токен noreturn указывает, что функция не возвращается. Он должен появляться не более одного раза в каждом списке атрибутов, и не должно присутствовать атрибут-аргумент-предложение. Атрибут может быть применен к идентификатору объявления в объявлении функции. Первое объявление функции должно указывать атрибут noreturn, если любое объявление этой функции указывает атрибут noreturn. Если функция объявлена ​​с атрибутом noreturn в одной единицы перевода, и одна и та же функция объявлена ​​без атрибута noreturn в другой единицы перевода, программа плохо сформирована; не требуется диагностика.

Я признаю, что эта формулировка, как есть, не запрещает атрибуту появляться в другом месте, но, несмотря на отсутствие доказательств в каком-либо стандарте для него, я не думаю, что это предназначено для работы с объявлениями лямбда.

Следовательно, Clang был бы правильным.

Может или не может быть сказано, что было предложение заплатки Clang, чтобы разрешить атрибуты noreturn в стиле GCC на lambdas, но а не стандартная форма.

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