Я думаю, вы что-то упустили, здесь.
статическая функция?
Объявление статической функции сделает ее "скрытой" в модуле компиляции.
Имя, имеющее область имен (3.3.6), имеет внутреннюю связь, если это имя
- переменная, функция или шаблон функции, которые явно объявлены статическими;
3,5 / 3 - C ++ 14 (n3797)
Когда имя имеет внутреннюю связь, обозначаемая им сущность может именоваться именами из других областей в той же единице перевода.
3,5 / 2 - C ++ 14 (n3797)
Если вы объявите эту статическую функцию в заголовке, то все модули компиляции, включая этот заголовок, будут иметь свою собственную копию функции.
Дело в том, что если внутри этой функции есть статические переменные, у каждого модуля компиляции, включая этот заголовок, также будет своя собственная, личная версия.
встроенная функция?
Объявление его встроенным делает его кандидатом на встраивание (в настоящее время это не так много значит для C ++, так как компилятор будет встроенным или нет, иногда игнорируя тот факт, что ключевое слово inline присутствует или отсутствует):
Объявление функции (8.3.5, 9.3, 11.3) со встроенным спецификатором объявляет встроенную функцию. Встроенный спецификатор указывает реализации, что внутренняя замена тела функции в точке вызова должна быть предпочтительнее обычного механизма вызова функции. Реализация не требуется для выполнения этой внутренней замены в точке вызова; однако, даже если эта встроенная подстановка опущена, другие правила для встроенных функций, определенные в 7.1.2, все равно должны соблюдаться.
7.1.2 / 2 - C ++ 14 (n3797)
В заголовке у него есть интересный побочный эффект: встроенная функция может быть определена несколько раз в одном и том же модуле, и компоновщик просто объединит «их» в один (если они не были встроены по причине компилятора).
Для статических переменных, объявленных внутри, в стандарте конкретно сказано, что одна и только одна из них:
Статическая локальная переменная во внешней встроенной функции всегда ссылается на один и тот же объект.
7.1.2 / 4 - C ++ 98 / C ++ 14 (n3797)
(функции по умолчанию являются внешними, поэтому, если вы не пометите свою функцию как статическую, это относится к этой функции)
Это имеет преимущество «статического» (то есть его можно определить в заголовке) без его недостатков (оно существует не более одного раза, если оно не встроено)
статическая локальная переменная?
Статические локальные переменные не имеют связи (на них нельзя ссылаться по имени вне области их действия), но имеют статическую продолжительность хранения (т. Е. Они глобальные, но их создание и уничтожение подчиняются определенным правилам).
статический + встроенный?
Смешивание inline и static будет иметь последствия, которые вы описали (даже если функция встроенная, статической переменной внутри не будет, и вы получите столько статических переменных, сколько у вас будет единиц компиляции, включая определение ваши статические функции).
Ответ на дополнительный вопрос автора
С тех пор как я написал вопрос, я попробовал его в Visual Studio 2008. Я попытался включить все параметры, которые заставляют VS работать в соответствии со стандартами, но, возможно, я пропустил некоторые из них. Вот результаты:
Когда функция просто «встроенная», есть только одна копия статической переменной.
Когда функция «статическая встроенная», копий столько же, сколько единиц перевода.
Реальный вопрос сейчас заключается в том, должны ли вещи быть такими, или это особенность компилятора Microsoft C ++.
Итак, я полагаю, у вас есть что-то вроде этого:
void doSomething()
{
static int value ;
}
Вы должны понимать, что статическая переменная внутри функции, проще говоря, глобальная переменная, скрытая для всех, кроме области действия функции, означая, что только функция, в которой она объявлена, может достичь ее.
Встраивание функции ничего не изменит:
inline void doSomething()
{
static int value ;
}
Будет только одна скрытая глобальная переменная. Тот факт, что компилятор попытается встроить код, не изменит тот факт, что существует только одна глобальная скрытая переменная.
Теперь, если ваша функция объявлена статической:
static void doSomething()
{
static int value ;
}
Тогда он является «закрытым» для каждой единицы компиляции, что означает, что каждый CPP-файл, включая заголовок, в котором объявлена статическая функция, будет иметь свою собственную частную копию функции, включая свою собственную частную копию глобальной скрытой переменной, таким образом, как много переменных, так как есть единицы компиляции, включая заголовок.
Добавление «inline» к «static» функции со «static» переменной внутри:
inline static void doSomething()
{
static int value ;
}
имеет тот же результат, что и не добавление этого ключевого слова "inline", что касается статической переменной внутри.
Таким образом, поведение VC ++ правильное, и вы ошибаетесь в истинном значении «inline» и «static».