Когда следует рассмотреть возможность использования статических функций, определенных в области видимости файла?
Я обычно использую их, когда задача, выполняемая в одной такой функции, на самом деле не принадлежит функциям-членам какого-либо класса, и когда такая задача необходима (неоднократно) только в определенном исходном файле.
Соответствует ли мое использование тому, почему эта функция существует? Или я угоняю концепцию, которая предназначена для чего-то другого?
Это вполне допустимое использование статических функций области файла, но имейте в виду, что такое использование статики уже давно не рекомендуется. Обычно вместо этого предпочитают использовать анонимные пространства имен.
Я делаю аналогичную вещь, когда имеет смысл иметь функции и / или данные, которые не являются частью интерфейса класса, а скорее деталями реализации.
Но я не использую ключевое слово static. Вместо этого я помещаю функции и / или данные в безымянное пространство имен.
Во-первых, термин, который вы ищете внутренняя связь. Ваш вопрос действительно должен быть: «Какие объекты должны иметь внутреннюю связь?» static
Ключевое слово, или, альтернативно, безымянные пространства имен, являются просто механизмами реализации для достижения внутренней связи.
Теперь ответ должен быть очевидным: все сущности, которые требуются только внутри одного единственного блока перевода, могут иметь внутреннюю связь, и в этом есть свои преимущества: во-первых, компилятор может использовать информацию, которую сущность никогда не сможет увидеть любым другим модулем перевода, так что он может, например, избежать испускания кода, который может потребоваться в противном случае, или встроенного более агрессивно. Другая причина заключается в том, что вы сводите к минимуму риск случайных нарушений ODR, если вы случайно выбрали имя, которое также используется локально в каком-либо другом TU.
Типичный пример такой:
my_lib.hpp:
#ifndef H_MY_LIB
#define H_MY_LIB
namespace foo
{
void do_an_awesome_thing(void * p, std::size_t n);
}
#endif
my_lib.cpp:
#include "my_lib.hpp"
namespace foo
{
namespace
{
void helper(void * p) { /* ... */ }
bool aux(std::size_t n, float f) { /* ... */ }
constexpr char usage[] = R"(This is how you do it...)";
constexpr float some_factor = 1.25;
}
void do_an_awesome_thing(void *p, std::size_t n)
{
if (!aux(n, some_factor)) { LOG_AND_DIE(usage); }
helper(p);
}
}
Теперь вы можете быть уверены, что ваш переводческий модуль не налагает чрезмерного бремени времени соединения на оставшуюся часть вашей программы.
Расположение безымянного пространства имен — дело вкуса; вы можете иметь его либо внутри обычного пространства имен, либо на верхнем уровне. Эффект тот же.