group-telegram.com/cxx95/37
Last Update:
#creepy
Двуликий inline для функций
Так вышло, что сейчас в C++ ключевое слово inline
для функций (точнее, само понятие inline
-функции) наделяет их двумя абсолютно ортогональными друг другу effective смыслами. Понятно, что один смысл вытек из другого, но все равно это раздельные сущности. Это:
(1) [dcl.inline].2: Подсказка компилятору о том, что более предпочтительна подстановка кода из функции в место вызова, чем сам вызов функции. (В компиляторе Clang в LLVM IR этот атрибут у функции называется inlinehint
)
(2) [dcl.inline].6: Правило, что у функции может быть несколько определений (definition) за программу. Для отсутствия UB это должны быть одинаковые определения - что естественным образом соблюдается, т.к. обычно метод определен в хидере. (В компиляторе атрибут у функции называется linkonce_odr
)
Получается, что у функции есть два атрибута - inlinehint
и linkonce
.
Прикол в том, что:
Стандарт написан так, что inlinehint
подразумевается только у функций, где явно написан спецификатор inline
.
Clang выполняет именно это, т.е. inlinehint
ставится тогда и только тогда, когда есть спецификатор inline
.
То есть получается вот что: inline int random() { return 4; }
будет И inlinehint
, И linkonce
.
А вот методы, которые по Стандарту являются implicit inline functions, например:
(*) инстанциации шаблонов
(*) default и deleted члены классов, и их неявные методы
(*) методы, чей definition
находится внутри definition
класса
(*) constexpr
- и consteval
-функции (на самом деле только constexpr
, т.к. consteval
"испаряется" и в LLVM IR его код тупо не попадает)
... они только linkonce
. Надо все равно писать ключевое слово inline
, чтобы было linkonce
+inlinehint
.
Если бы я мог редактировать стандарт, я бы переименовал inline functions в linkonce functions, потому что текущее описание в Стандарте сильно запутывает...
Интересные вопросы:
(1) Так ли сильно влияет наличие атрибута inlinehint
на компиляцию? Я слышал, что компиляторы уже давно не обращают внимание на подобные подсказки...
Влияет практически незаметно. Порог для инлайнинга у обычного метода 225 попугаев, для inlinehint-метода 325 попугаев (ссылка на код), а для реальной разницы нужно ~1000 попугаев.
То есть в 99% кейсов inline constexpr void foo()
и constexpr void foo()
будут вести себя одинаково, однако в clang-tidy не принимают патч на удаление redundant inline, потому что остается какой-то непонятный 1% кейсов.
(2) Почему один атрибут вытекает из другого, если они ортогональны?
Чтобы компилятор мог в translation unit заинлайнить (inlinehint
) функцию, TU нужно "видеть" исходник этой функции, то есть её тело. В общем случае это невозможно обеспечить, потому что если у нас N штук TU, то будет N определений одной и той же функции и линкер сломается. Поэтому эта функция должна являться linkonce
, чтобы не нарушился ODR.
BY C++95
Warning: Undefined variable $i in /var/www/group-telegram/post.php on line 260
Share with your friend now:
group-telegram.com/cxx95/37