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