Полагаю, вы здесь что-то упускаете.
статическая функция?
Объявление функции статической сделает ее «скрытой» в ее модуле компиляции.
Имя, имеющее область пространства имен (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)
В заголовке это имеет интересный побочный эффект: встроенная функция может быть определена несколько раз в одном и том же модуле, и компоновщик просто объединит «их» в один (если они не были встроены по причине компилятора).
Для статических переменных, объявленных внутри, в стандарте конкретно говорится, что есть одна и только одна из них:
Статическая локальная переменная во встроенной функции extern всегда ссылается на один и тот же объект.
7.1.2 / 4 - C ++ 98 / C ++ 14 (n3797)
(функции по умолчанию являются extern, поэтому, если вы специально не отметили свою функцию как статическую, это относится к этой функции)
У этого есть преимущество "статики" (т.е. он может быть определен в заголовке) без недостатков (он существует не более одного раза, если он не встроен)
статическая локальная переменная?
Статические локальные переменные не имеют связи (на них нельзя ссылаться по имени вне их области видимости), но имеют статическую продолжительность хранения (т. Е. Глобальные, но их создание и уничтожение подчиняются определенным правилам).
статический + встроенный?
Смешивание встроенных и статических будет иметь описанные вами последствия (даже если функция встроена, статическая переменная внутри не будет, и вы закончите с таким количеством статических переменных, сколько у вас есть единиц компиляции, включая определение ваших статических функций ).
Ответ на дополнительный вопрос автора
Поскольку я написал вопрос, я попробовал его с 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» к «статической» функции со «статической» переменной внутри:
inline static void doSomething()
{
static int value ;
}
имеет тот же результат, что и отсутствие этого "встроенного" ключевого слова, что касается статической переменной внутри.
Итак, поведение VC ++ правильное, и вы ошибаетесь в истинном значении слов «встроенный» и «статический».