C++ Embedded

@channel_cppembedded
Долой ()! Мало кто знает, но я распечатываю каждый опубликованный черновик стандарта. Читать их, конечно, не успеваю, но заботливо кладу на полочку. Вдруг интернет совсем заблокируют, электричество закончится или еще какая нужда приключится. Вот, растапливая печку, я листал старенький n3242 за 2011 год и увидел интересную деталь в разделе 5.1.2 Lambda expressions [expr.prim.lambda]. Речь, конечно, про объявление лямбда-выражения: lambda-introducer lambda-declarator[opt] compound-statementПервая часть, lambda-introducer, описывает захват лямбды, последняя - непосредственно блок кода функции. Средняя часть определяет сигнатуру функции: ( parameter-declaration-clause ) mutable[opt]exception-specification[opt] attribute-specifier-seq[opt] trailing-return-type[opt]Когда-то я не обратил на это внимания, но сейчас, после обнародования всех тех ужасов, что GCC вытворяет с лямбдами, не мог пройти мимо. Несчастное ключевое слово mutable приковано к списку параметров! И наверняка против его воли. Это значит, что лямбде разрешается быть такой: []{}, либо такой: []() mutable {}, но она не может быть [] mutable {}. Оказывается, не по стандарту это, не по понятиям. Так и пропадало бы это невинное и понятное, в общем-то, выражение с печатью изгоя на сигнатуре, но в июне 2018 года некто Alex Christensen из Apple и JF Bastien оттуда же (хотя потом убежит в Тойоту, но не осуждаем) написали предложение "Down with ()!" Мне нравится этот документ за самую краткую и четкую аннотацию, какую я видел: Предложение по удалению ненужных () из лямбд.Ни капли воды! Далее так же сухо подавалась суть. В настоящее время для лямбда-выражений без параметров не обязательно писать круглые скобки. В спецификации [expr.prim.lambda] (раздел 8.4.5, пункт 4) по этому поводу сказано следующее: Если лямбда-выражение не включает в себя лямбда-декларатор (lambda-declarator), оно интерпретируется так, как если бы лямбда-декларатор был пуст: ().Это позволяет опустить неиспользуемые () в простых лямбдах. 𝚊𝚞𝚝𝚘 𝚠𝚒𝚝𝚑𝙿𝚊𝚛𝚎𝚗 = [𝚜𝟷 = 𝚜𝚝𝚍::𝚖𝚘𝚟𝚎(𝚜𝟷)] () {}; 𝚊𝚞𝚝𝚘 𝚗𝚘𝚂𝚎𝚊𝚗 = [𝚜𝟸 = 𝚜𝚝𝚍::𝚖𝚘𝚟𝚎(𝚜𝟸)] { /* Так можно */ }; Конкретно эти лямбды владеют строками, но не могут их изменить, s1 и s2 объявлены как const (т.к. лямбда по умолчанию const), для этого нам нужно ключевое слово mutable. 𝚊𝚞𝚝𝚘 𝚠𝚒𝚝𝚑𝙿𝚊𝚛𝚎𝚗 = [𝚜𝟷 = 𝚜𝚝𝚍::𝚖𝚘𝚟𝚎(𝚜𝟷)] () 𝚖𝚞𝚝𝚊𝚋𝚕𝚎 { 𝚜𝟷 += "𝚍"; }; 𝚊𝚞𝚝𝚘 𝚗𝚘𝚂𝚎𝚊𝚗 = [𝚜𝟸 = 𝚜𝚝𝚍::𝚖𝚘𝚟𝚎(𝚜𝟸)] 𝚖𝚞𝚝𝚊𝚋𝚕𝚎 { /* Ошибка! */ 𝚜𝟸 += "𝚍"; }; Как ни странно, текущий стандарт требует наличия пустых скобок при применении mutable ключевого слова. Это правило контринтуитивно, приводит к распространенным синтаксическим ошибкам и загромождает код. При компиляции clang мы даже получаем синтаксическую ошибку, указывающую на то, что компилятор точно знает, что происходит: example.cpp:11:54: error: lambda requires '()' before 'mutable'Собственно, GCC 10 реагировал схожим образом, а уже GCC 11 стал заметно мягче относиться к нарушению стандарта: warning: parameter declaration before lambda declaration specifiers only optional with '-std=c++23' or '-std=gnu++23' [-Wc++23-extensions]"А чего такого? - удивленно таращится на тебя компилятор, - в c++23 исправили же!" Действительно, ребята добились своего, mutable оторвали от списка параметров. Однако в с++20 это все еще грех!
Если у вас установлено приложение,
вы можете сразу перейти в канал