Нельзя указать extern
для функции-члена.
Стандарт поясняет это в [dcl.stc]/5
:
Спецификатор extern может применяться только к именам переменных и функции. Спецификатор extern нельзя использовать в объявлении членов класса или параметров функции.
Когда вы используете extern, вы говорите компилятору, что вы объявляете переменную или функцию, но не определяете их. В случае функций-членов это не требуется: они всегда могут быть объявлены в теле класса без определения:
class A {
public:
void f(); // you can define it in which ever compilation unit (cpp) you want
};
...
// Else where...may be in another cpp
void A::f() {...}
Компоновщик разрешит символы при необходимости.
Встроенный не очень полезен
Стандарт в [dcl.inline]/2
говорит, что встроенный не гарантируется:
Встроенный спецификатор указывает реализации, что встроенная замена тела функции в точке вызова должно быть предпочтительнее обычного механизма вызова функции. Реализация не требуется для выполнения этой внутренней подстановки в точке вызова;
Кроме того, [dcl.inline]/6
объясняет, что inline
и определенные eleswhere не предназначены для работы хорошо:
Встроенная функция или переменная должна быть определена в каждой единице перевода, в которой она используется odr, и должна иметь абсолютно одинаковое определение в каждом случае.
(odr говорит, что все определения должны каждый раз быть точно таким же определением) (в каждой единице перевода означает в каждом cpp или включенных в него заголовках)
На С другой стороны, глобальный оптимизатор некоторых современных компиляторов способен достичь тех же эффектов производительности, что и встроенные функции, и это распространяется на единицы компиляции (cpp).
Спецификация реализации c forceinline
MSV C 2019 тщательно использует inline
, проводя анализ затрат / выгод, чтобы решить, стоит ли включать.
forceinline
позволяет вам отменить решение компилятора. Но он отвечает всем требованиям обычного inline
: поэтому вам нужно иметь определение функции в том же модуле компиляции, чтобы она заработала.