Функции
Объявления, перегрузка, аргументы по умолчанию, inline, лямбды и callable-объекты.
32 вопросов
JuniorТеорияОчень частоПередача аргументов по значению, ссылке и указателю — когда что использовать?
Передача аргументов по значению, ссылке и указателю — когда что использовать?
По значению: маленькие тривиально копируемые или нужна своя копия. По const T&: по умолчанию для крупнее указателя без изменений. По T&: меняем вызывающего. По T*: когда null значим.
Типичные ошибки
- ✗Передавать большие объекты по значению в производительно-критичном коде — вызывает ненужное копирование
- ✗Использовать не-const ссылку, когда значение только читается — вводит вызывающих в заблуждение, что объект может быть изменён
- ✗Разыменовывать указатель-параметр без проверки на null, когда указатель может быть null по контракту
Уточняющие вопросы
- →Что такое паттерн 'sink parameter' и когда передача по значению +
std::moveпревосходит перегрузку по lvalue/rvalue ссылкам? - →Чем семантически отличается передача по
T&&(rvalue-ссылка) от передачи поT?
JuniorДебаггингОчень частоЧто произойдёт, если вернуть ссылку на локальный объект?
Что произойдёт, если вернуть ссылку на локальный объект?
Локальный объект уничтожается при возврате из функции. Возвращённая ссылка сразу становится висячей — любое разыменование UB. Компиляторы предупреждают с -Wall.
Типичные ошибки
- ✗Думать, что ссылка 'может' работать, потому что стековая память ещё не была переиспользована — это всё равно UB
- ✗Возвращать
const std::string&из геттера, который строит строку локально — временный объект уничтожается - ✗Не замечать предупреждение компилятора — оно почти всегда правильно указывает на висячие ссылки
Уточняющие вопросы
- →Как RVO/NRVO устраняет стоимость возврата по значению для больших объектов?
- →Безопасен ли возврат ссылки на
static-локальную переменную в многопоточной программе?
JuniorТеорияОчень частоЧто такое лямбда? Как захватывать внешние переменные?
Что такое лямбда? Как захватывать внешние переменные?
Анонимный функциональный объект inline. Захваты: [=] значение, [&] ссылка, [x]/[&x], [y = expr] init, [*this] копия. Без захватов конвертируется в указатель на функцию.
Типичные ошибки
- ✗Использовать захват
[&]в лямбде, хранящейся дольше захваченных переменных — висячие ссылки - ✗Забывать, что
[=]в функции-члене захватываетthisпо указателю — используйте[*this](C++17) для безопасной копии - ✗Ожидать, что два одинаковых выражения лямбды имеют одинаковый тип — у каждой лямбды уникальный тип
Уточняющие вопросы
- →Что такое обобщённая лямбда (C++14) и как она связана с шаблонами функций?
- →Когда вы использовали бы
mutable-лямбду?
JuniorТеорияОчень частоЧто такое перегрузка функций и как работает разрешение перегрузки?
Что такое перегрузка функций и как работает разрешение перегрузки?
Несколько функций имеют одно имя, но различаются типами или числом параметров. Компилятор выбирает: точное совпадение, продвижения, стандартные преобразования, пользовательские преобразования.
Типичные ошибки
- ✗Попытка перегрузить функцию только по возвращаемому типу — в C++ это недопустимо
- ✗Создание неоднозначных перегрузок, вынуждающих компилятор выдавать ошибку
- ✗Забывать, что аргументы по умолчанию могут создать неоднозначность с существующими перегрузками
Уточняющие вопросы
- →Как декорирование имён (name mangling) связано с перегрузкой?
- →Что происходит, если ни одна перегрузка не совпадает точно?
MiddleДебаггингОчень частоПочему эта возвращённая лямбда читает освобождённую память?
Почему эта возвращённая лямбда читает освобождённую память?
Лямбда захватывает count по ссылке ([&]), но count уничтожается, когда makeCounter возвращается, поэтому вызов возвращённого std::function читает висячую ссылку — UB. Решение: захват по значению, [count]() mutable { return ++count; }.
Типичные ошибки
- ✗Считать, что захват по ссылке продлевает время жизни захваченной переменной
- ✗Винить std::function вместо захвата по ссылке
- ✗Думать, что добавление mutable исправляет то, что на деле является ошибкой времени жизни
Уточняющие вопросы
- →Когда захват по ссылке в лямбде действительно безопасен?
- →Почему захвату по значению нужен
mutable, чтобы его можно было изменять?
JuniorТеорияЧастоКаковы правила применения аргументов по умолчанию и какие подводные камни они создают?
Каковы правила применения аргументов по умолчанию и какие подводные камни они создают?
Аргументы по умолчанию задаются справа налево (последние первые). Разрешаются в точке вызова по видимому там объявлению, а не по определению.
Типичные ошибки
- ✗Переопределение аргумента по умолчанию в другой единице трансляции — неопределённое поведение
- ✗Комбинирование аргументов по умолчанию с перегрузками, создающее неоднозначные вызовы
- ✗Ожидание, что виртуальные переопределения наследуют аргументы по умолчанию от базового класса
Уточняющие вопросы
- →Почему виртуальные функции и аргументы по умолчанию плохо сочетаются?
- →Что произойдёт, если две единицы трансляции видят разные значения по умолчанию для одной функции?
JuniorТеорияЧастоКаков порядок вычисления аргументов функции в C++?
Каков порядок вычисления аргументов функции в C++?
Порядок вычисления аргументов не определён — f(a++, a++) — UB. C++17 упорядочил вызываемую до аргументов, но порядок аргумент-к-аргументу по-прежнему не определён.
Типичные ошибки
- ✗Полагать порядок слева направо — распространён в x86 calling convention, но стандартом не гарантирован
- ✗Изменять переменную в одном аргументе и читать её в другом — классический пример UB
- ✗Думать, что C++17 исправил все проблемы порядка — он только гарантировал вычисление вызываемой до аргументов, но не порядок между аргументами
Уточняющие вопросы
- →Какие правила упорядочения ввёл C++17, которых не было в C++14?
- →Как переписать
f(i++, i++), чтобы намерение было ясным и поведение было определённым?
JuniorТеорияЧастоЧто такое указатель на функцию и как его объявить?
Что такое указатель на функцию и как его объявить?
Хранит адрес функции с конкретной сигнатурой. Объявление: int (*fp)(double, double);. Вызов: fp(a, b). Для читаемости — using BinaryOp = int(*)(double, double);.
Типичные ошибки
- ✗Путать указатель на функцию с указателем на функцию-член — указатели на функции-члены имеют другой, несовместимый тип
- ✗Не использовать
typedef/usingдля типа указателя на функцию — синтаксис сырого объявления нотационно трудночитаем - ✗Хранить захватывающую лямбду в сыром указателе на функцию — только не-захватывающие лямбды неявно конвертируются
Уточняющие вопросы
- →В чём разница между
std::functionи сырым указателем на функцию с точки зрения накладных расходов? - →Как хранить указатель на не-статическую функцию-член и вызывать его позже?
JuniorТеорияЧастоЧто такое ленивые вычисления (short-circuit evaluation) в C++?
Что такое ленивые вычисления (short-circuit evaluation) в C++?
&& и || вычисляют левый операнд первым; если результат определён — правый пропускается. Гарантировано стандартом и упорядочено. Тернарный ? : тоже ленив. Перегруженные &&/|| — НЕТ.
Типичные ошибки
- ✗Полагаться на ленивое вычисление с перегруженными
&&/||— перегруженные операторы всегда вычисляют обе стороны - ✗Размещать ресурсоёмкое по побочным эффектам выражение справа, ожидая, что оно всегда выполнится — не выполнится, если левая часть определяет результат
- ✗Не знать, что оператор запятая тоже упорядочивает слева направо, но
|и&не вычисляются лениво
Уточняющие вопросы
- →Чем
std::logical_andиstd::logical_orиз C++23 отличаются от&&и||? - →Когда ленивое вычисление полезно для защиты от разыменования нулевого указателя?
JuniorТеорияЧастоЧто такое стековый кадр функции и что может вызвать stack overflow?
Что такое стековый кадр функции и что может вызвать stack overflow?
Область конкретного вызова: локальные переменные, сохранённые регистры, адрес возврата, аргументы. Stack overflow — превышение лимита стека вложенными вызовами или большими локальными.
Типичные ошибки
- ✗Считать, что стек растёт без практических ограничений
- ✗Выделять многомегабайтные массивы как локальные переменные
- ✗Путать стек вызовов с контейнером std::stack
Уточняющие вопросы
- →Где хранятся машинные инструкции функций?
- →Как избежать stack overflow в рекурсивном коде?
MiddleТеорияЧастоЧто такое argument-dependent lookup (ADL), и когда он удивляет?
Что такое argument-dependent lookup (ADL), и когда он удивляет?
ADL добавляет namespace типов аргументов вызова к множеству поиска неквалифицированного имени функции. Благодаря этому swap(a, b) или operator<< находят нужную перегрузку без квалификатора. Удивляет тем, что молча подтягивает непреднамеренную перегрузку из namespace аргумента.
Типичные ошибки
- ✗Писать
std::swap(a, b)вместо идиомыusing std::swap; swap(a, b), дающейADLнайти кастомныйswap - ✗Считать, что квалифицированный вызов
ns::f(x)всё ещё делаетADL— квалификация его полностью отключает - ✗Класть свободную функцию в
namespace std, чтобы её нашёлADL, вместо размещения рядом с типом
Уточняющие вопросы
- →Почему рекомендуется двухшаговая идиома
using std::swap; swap(a, b)? - →Как hidden friends взаимодействуют с ADL и обычным поиском?
MiddleТеорияЧастоКак работает C++14 return-type deduction и когда он не работает?
Как работает C++14 return-type deduction и когда он не работает?
auto f() { return expr; } выводит тип возврата по тем же правилам, что auto x = expr. Все return должны давать один тип. Рекурсия только после первого return.
Типичные ошибки
- ✗Два
returnс разными типами — ошибка компиляции - ✗Рекурсивный вызов до первого
return— компилятор ещё не вывел тип - ✗Forward-declare
auto f();и определение в другом файле — вызывающий не знает тип
Уточняющие вопросы
- →Почему
decltype(auto)важен для perfect-forwarding возврата? - →Чем
auto-возврат лямбды отличается от функции?
MiddleТеорияЧастоЧто значит constexpr у функции и как это эволюционировало в C++14/17/20?
Что значит constexpr у функции и как это эволюционировало в C++14/17/20?
Разрешает вычисление в compile-time при константных аргументах; иначе — в рантайме. C++11 — один return. C++14 — циклы, локальные. C++20 — virtual, аллокации, std::vector/std::string.
Типичные ошибки
- ✗Помечать всё
constexprбез нужды — не вредит, но раздувает API - ✗Вызывать не-constexpr функцию внутри constexpr — молча превращается в рантайм-вызов
- ✗Путать
constexprиconst—constexprдля объектов влечёт const, но у функций речь о вычислимости
Уточняющие вопросы
- →Чем
constexprотличается отconsteval? - →Что такое
std::is_constant_evaluated()и когда его использовать?
MiddleДебаггингЧастоКакие подводные камни у дефолтных аргументов в виртуальных функциях и между TU?
Какие подводные камни у дефолтных аргументов в виртуальных функциях и между TU?
Дефолты привязываются статически по типу указателя/ссылки. Base* b = new Derived; b->f(); берёт дефолт Base, хотя выполняется Derived::f; дефолт = 2 в переопределении мёртв.
Типичные ошибки
- ✗Переопределить virtual с другим дефолтом — вызов берёт дефолт базового класса
- ✗Разные дефолты в двух заголовках — нарушение ODR
- ✗Дефолты, зависящие от глобалов — неочевидное поведение в точке вызова
Уточняющие вопросы
- →Почему стандарт выбрал статическое связывание для дефолтов?
- →Как
std::optional/ sentinel чисто заменяют дефолтные аргументы?
MiddleТеорияЧастоЧто такое функтор? Напишите пример.
Что такое функтор? Напишите пример.
Функтор (функциональный объект) — любой класс, перегружающий operator(). В отличие от указателя на функцию, хранит состояние в членах и инлайнится — без накладных расходов на стирание типа.
Типичные ошибки
- ✗Забывать помечать
operator()какconst, если функтор не изменяет состояние — предотвращает использование сconst-алгоритмами - ✗Хранить дорогостоящее для копирования состояние в функторе, передаваемом по значению в алгоритм — STL может внутренне копировать функтор
- ✗Использовать
std::function, когда параметр шаблона принимает callable —std::functionдобавляет ненужные накладные расходы на удаление типа
Уточняющие вопросы
- →В чём разница между состоятельным функтором и лямбдой с захватами?
- →Как
std::bindсоотносится с функторами и почему лямбды в основном вытеснили его?
MiddleТеорияЧастоЧто на самом деле гарантирует ключевое слово inline в современном C++?
Что на самом деле гарантирует ключевое слово inline в современном C++?
inline снимает ограничение ODR — одно определение может быть в нескольких TU (нужно для функций в заголовках). Подсказка о встраивании в точку вызова современными компиляторами игнорируется.
Типичные ошибки
- ✗Предположение, что inline всегда устраняет накладные расходы на вызов
- ✗Мнение, что inline придаёт функции внутреннее связывание
- ✗Размещение не-inline определений в заголовках в ожидании отсутствия ошибок компоновщика
Уточняющие вопросы
- →В чём разница между inline и __forceinline / __attribute__((always_inline))?
- →Когда стоит использовать NOINLINE?
MiddleТеорияЧастоЧто означает mutable у лямбды и чем опасен захват this?
Что означает mutable у лямбды и чем опасен захват this?
По умолчанию operator() у лямбды const — захваченные по значению менять нельзя. mutable снимает const. Захват this хранит указатель — висячий, если объект умер раньше.
Типичные ошибки
- ✗Думать, что mutable меняет исходную переменную, захваченную по значению
- ✗Захватывать this в async-callback без контроля времени жизни объекта
- ✗Использовать [&] в callback, который живёт дольше текущей области
Уточняющие вопросы
- →Как shared_ptr или weak_ptr помогают в async-callback?
- →В чём разница между [this] и [*this]?
MiddleТеорияЧастоЧто такое name mangling в C++ и как он работает с extern "C"?
Что такое name mangling в C++ и как он работает с extern "C"?
Mangling кодирует сигнатуру (параметры, namespace, шаблоны) в имя символа, чтобы линкер различал перегрузки. У каждого ABI своя схема. extern "C" отключает mangling для C-interop.
Типичные ошибки
- ✗Забыть
extern "C"у функции, вызываемой из C — link error - ✗Пытаться перегрузить
extern "C"— mangling нет, поэтому нельзя - ✗Несовместимые ABI при линковке объектников разных компиляторов
Уточняющие вопросы
- →Как читать mangled-имена (
c++filt)? - →Почему на Linux Itanium ABI, несмотря на название?
MiddleПроизводительностьЧастоКакова рантайм-стоимость виртуального вызова и когда это важно?
Какова рантайм-стоимость виртуального вызова и когда это важно?
Две indirection: загрузка vptr, загрузка указателя на функцию из vtable, прыжок. Стоимость — несколько ns плюс возможный cache miss; важнее то, что вызов не инлайнится.
Типичные ошибки
- ✗Профилировать без
-O2и делать вывод о медленности virtual - ✗Добавлять
virtualк листовым методам, которым подходитfinal(теряется devirt) - ✗Выбирать CRTP для мелкого полиморфизма с парой типов — overkill
Уточняющие вопросы
- →Как компилятор делает devirtualisation?
- →Почему
finalпомогает даже у класса (не только у метода)?
SeniorТеорияЧастоЧто такое perfect forwarding и как его реализовать?
Что такое perfect forwarding и как его реализовать?
Сохраняет value category (lvalue/rvalue) и cv-квалификацию при передаче. Шаблон: template<class... A> void wrap(A&&... a) { f(std::forward<A>(a)...); }. Без forward rvalue становятся lvalue.
Типичные ошибки
- ✗Использовать
std::move(args)...вместоstd::forward<Args>(args)...— ошибочно перемещает lvalue - ✗Путать
T&&в не-шаблоне с forwarding-ссылкой — там это просто rvalue ref - ✗Перегружать forwarding-ref и конкретные типы — forwarding-ref обычно побеждает и перехватывает вызовы
Уточняющие вопросы
- →Что такое reference collapsing?
- →Чем C++20
std::forward_likeотличается отstd::forward?
MiddleТеорияИногдаЧто такое контракт функции (предусловия, постусловия, инварианты)?
Что такое контракт функции (предусловия, постусловия, инварианты)?
Обязательства между вызывающим и вызываемым. Предусловия — выполняет вызывающий. Постусловия — гарантирует функция. Инварианты — свойства класса после публичных операций.
Типичные ошибки
- ✗Молча обрабатывать нарушенные предусловия вместо assert — скрывает баги вызывающего и приводит к более сложным для отладки сбоям далее
- ✗Не документировать контракт — вызывающие не могут знать, что допустимо, без документации
- ✗Проверять предусловия в release-сборках, когда они дорогостоящие — используйте
assert, который убирается при NDEBUG
Уточняющие вопросы
- →Чем
assert,[[expects]]и бросание исключений отличаются как механизмы проверки предусловий? - →Что такое Design by Contract (DbC) и какие языки поддерживают его нативно?
MiddleТеорияИногдаЧто такое обобщённая лямбда, и как она связана с шаблоном функции?
Что такое обобщённая лямбда, и как она связана с шаблоном функции?
Обобщённая лямбда (C++14) использует auto для параметра, делая её operator() шаблоном-членом. Каждый различный тип аргумента инстанцирует отдельный operator(), точно как шаблон функции. Замыкание — один тип; шаблонным является лишь оператор вызова, который подстраивается под точку вызова.
Типичные ошибки
- ✗Думать, что каждый вызов с
auto-параметром создаёт новый тип замыкания — тип один, шаблонным являетсяoperator() - ✗Ожидать, что два типа аргументов разделят одно тело
operator()— каждый тип инстанцирует своё, со своими ошибками - ✗Забывать
decltype(auto)илиauto&&для параметров, которые должны идеально пробрасываться внутри тела
Уточняющие вопросы
- →Как добавить лямбде явный список параметров шаблона (C++20)?
- →Когда обобщённая лямбда предпочтительнее именованного шаблона функции?
MiddleТеорияИногдаЧто такое init-capture, и зачем он нужен для захвата переменной перемещением?
Что такое init-capture, и зачем он нужен для захвата переменной перемещением?
Init-capture (C++14) вводит новый член замыкания с инициализатором: [p = std::move(ptr)]. Обычный [ptr] только копирует; синтаксис захвата не умеет выразить перемещение. Init-capture позволяет инициализировать член любым выражением — переместить в него unique_ptr либо вычислить значение.
Типичные ошибки
- ✗Пытаться захватить
unique_ptrчерез обычный[ptr]и получить ошибку об удалённом конструкторе копирования - ✗Забывать, что член init-capture инициализируется один раз при создании лямбды, а не на каждом вызове
- ✗Называть член init-capture так же, как исходную переменную, и путать, какую из них использует тело
Уточняющие вопросы
- →Как переместить член класса в лямбду внутри функции-члена?
- →Может ли init-capture использовать pack expansion в C++20?
MiddleКодИногдаРеализуйте минимальный механизм signal/slot с использованием лямбд и std::function
Реализуйте минимальный механизм signal/slot с использованием лямбд и std::function
Храните колбэки в std::vector<std::function<void()>> с token-id для disconnect, и пробегайте на emit(). Лямбды с захватами подходят — std::function стирает тип замыкания.
Типичные ошибки
- ✗Захват локальных переменных по ссылке, когда лямбда живёт дольше области видимости
- ✗Копирование
std::functionс большими захватами вместо предпочтительногоstd::move - ✗Игнорирование того, что
std::functionобычно даёт около 10-20% накладных расходов относительно прямого вызова из-за выделения памяти и стирания типа
Уточняющие вопросы
- →Как сделать подключение слотов потокобезопасным?
- →Что такое
std::move_only_functionи когда его стоит предпочестьstd::function?
MiddleТеорияИногдаКогда нужен std::mem_fn и когда его заменили лямбды?
Когда нужен std::mem_fn и когда его заменили лямбды?
std::mem_fn(&Class::method) адаптирует указатель на функцию-член в callable, принимающий объект первым. Полезен в STL-алгоритмах; современный код предпочитает лямбду.
Типичные ошибки
- ✗Использовать
std::bindтам, где лямбда понятнее — bind-композиция плохо читается - ✗Забывать, что
mem_fnпринимает и указатель, и ссылку, и автоматически выбирает - ✗Хранить результат
mem_fnв явном типе — на практике лучше auto
Уточняющие вопросы
- →Почему
std::bindпрактически вытеснен лямбдами? - →Как привязать часть аргументов и оставить другие свободными?
MiddleТеорияИногдаЧто такое trailing return type и когда он необходим?
Что такое trailing return type и когда он необходим?
auto f(args) -> ReturnType помещает тип возврата после параметров. Нужен, когда возврат зависит от параметров: auto add(T a, U b) -> decltype(a + b). Ещё нужен для SFINAE-friendly шаблонов.
Типичные ошибки
- ✗Просто
autoдля шаблонов, участвующих в overload resolution — вызывающий не может делать SFINAE по возврату - ✗Забывать, что
auto f() -> intидентичноint f()для не-шаблонов - ✗Смешивать
decltype(expr)с reference-collapsing в trailing return
Уточняющие вопросы
- →Чем
decltype(auto)отличается отautoв возвращаемом типе? - →Когда
auto-deduction в C++14 не работает и нужен-> T?
MiddleТеорияИногдаЧем C-style variadic-функции отличаются от variadic-шаблонов C++11?
Чем C-style variadic-функции отличаются от variadic-шаблонов C++11?
C-style ... с va_list не типобезопасен — callee «угадывает» типы через format string или sentinel; рассогласование — UB. Variadic-шаблоны C++11 template<class... A> типобезопасны: каждый аргумент сохраняет тип.
Типичные ошибки
- ✗Смешивать
va_listи variadic-шаблон в одном API - ✗Не использовать fold expressions:
(std::cout << ... << args)куда понятнее рекурсивной пары - ✗Передавать не-trivially-copyable через
va_list— UB
Уточняющие вопросы
- →Чем унарные fold expressions отличаются от бинарных?
- →Как
std::format(C++20) заменяет printf-style varargs безопасно?
SeniorТеорияИногдаКак noexcept(expr) даёт условный noexcept в шаблонах?
Как noexcept(expr) даёт условный noexcept в шаблонах?
noexcept(expr) вычисляет expr в compile-time и пробрасывает bool в noexcept-спецификацию. Шаблон: swap(T&, T&) noexcept(noexcept(swap(a.m, b.m))).
Типичные ошибки
- ✗Писать
noexcept(true)на функции, которая зовёт что-то бросающее — terminate в рантайме - ✗Забыть внешний
noexcept(...)и писатьnoexcept(swap(a, b))(это операнд!) — типичная опечатка - ✗Помечать move-ctor
noexcept, когда move члена бросает — terminate
Уточняющие вопросы
- →Почему стандартная библиотека требует noexcept-move для strong guarantee в vector?
- →Как вычисляется
is_nothrow_move_constructible_v?
SeniorПроизводительностьИногдаКогда компилятор делает tail-call optimisation в C++?
Когда компилятор делает tail-call optimisation в C++?
Стандарт C++ не требует TCO. GCC/Clang/MSVC делают tail-call, когда рекурсивный вызов — последняя операция при -O2/-O3, без деструкторов после и при совместимом ABI.
Типичные ошибки
- ✗Возвращать
std::move(recursive_call())— отключает TCO из-за обёртки - ✗Деструктор после рекурсивного вызова (локальная переменная с non-trivial dtor)
- ✗Компилировать в debug и удивляться отсутствию TCO
Уточняющие вопросы
- →Почему C++ не стандартизует TCO?
- →Как
[[clang::musttail]]меняет картину?
SeniorТеорияИногдаЧто такое операция INVOKE, и что унифицирует std::invoke?
Что такое операция INVOKE, и что унифицирует std::invoke?
INVOKE — абстрактное правило стандарта для вызова любого callable. std::invoke(f, args...) применяет его единообразно: свободные функции и функторы зовёт как f(args...), а для указателя на член трактует первый аргумент как объект, обрабатывая ссылки, указатели и reference_wrapper. На нём держатся std::bind, std::thread и std::function.
Типичные ошибки
- ✗Писать ветвящийся код для вызова свободной функции или указателя на член, когда
std::invokeуже унифицирует оба - ✗Считать, что
std::invokeдобавляет рантайм-стоимость — он полностью разрешается на компиляции и инлайнится - ✗Забывать, что
std::invoke_result_t/std::is_invocable_vопрашивают то же правило INVOKE в трейтах
Уточняющие вопросы
- →Чем
std::invoke_r(C++23) отличается отstd::invoke? - →Почему
std::bind,std::threadиstd::asyncзадают свой вызов через INVOKE?
SeniorТеорияРедкоЧто такое consteval и когда использовать его вместо constexpr?
Что такое consteval и когда использовать его вместо constexpr?
consteval (C++20) делает функцию immediate — каждый вызов обязан давать constant expression. В отличие от constexpr, fallback в рантайм невозможен. Для compile-time-only утилит.
Типичные ошибки
- ✗Пометить
constevalи пытаться вызвать с рантайм-аргументами - ✗Взять указатель на
consteval-функцию — ошибка - ✗Путать
constevalсconstinit(инициализирует переменную в compile-time)
Уточняющие вопросы
- →Как
constevalвзаимодействует сif consteval(C++23)? - →Зачем
consteval, еслиconstexprуже даёт compile-time?
SeniorТеорияРедкоЧто такое C++23 «deducing this» и какие задачи это решает?
Что такое C++23 «deducing this» и какие задачи это решает?
C++23 позволяет члену принимать this как явный параметр: void f(this Self&& self, ...). Шаблонизируется по value category и cv-квалификации — заменяет четыре перегрузки. Даёт CRTP без наследования.
Типичные ошибки
- ✗Пытаться
this->внутри deducing-this функции —thisнет, используйтеself. - ✗Помечать функцию
virtual— несовместимо - ✗Забывать forward: пишите
std::forward<Self>(self).memberдля сохранения value category
Уточняющие вопросы
- →Как deducing-this убирает необходимость в CRTP?
- →Почему deducing-this функция не может быть virtual?