我什么时候应该考虑使用在文件范围内定义的静态函数?
当在一个这样的函数中完成的任务并不真正属于任何类的成员函数并且只在某个源文件中(重复地)需要这样的任务时,我通常会使用它们。
我的使用是否符合此功能存在的原因?还是我在劫持一个用于其他目的的概念?
我什么时候应该考虑使用在文件范围内定义的静态函数?
当在一个这样的函数中完成的任务并不真正属于任何类的成员函数并且只在某个源文件中(重复地)需要这样的任务时,我通常会使用它们。
我的使用是否符合此功能存在的原因?还是我在劫持一个用于其他目的的概念?
这是对文件范围静态函数的完全有效的使用,但请记住,这种静态的使用已经被弃用了一段时间。通常首选使用匿名命名空间。
当函数和/数据不是类接口的一部分而是实现细节时,我会做类似的事情。
但我不使用关键字静态。相反,我将函数和/或数据放在一个未命名的命名空间中。
首先,您要查找的术语是内部链接。你的问题真的应该是:“哪些实体应该有内部联系?” 关键字或未命名的static
命名空间只是实现内部链接的实现机制。
现在答案应该很明显了:所有只需要在一个翻译单元内的实体都可以被赋予内部链接,这样做有好处:一是编译器可以利用一个实体永远看不到的信息由任何其他翻译单元,因此它可以例如避免发出可能需要的代码,或者更积极地内联。另一个原因是,如果您碰巧选择了一个也在其他 TU 中本地使用的名称,那么您可以最大限度地降低意外违反 ODR 的风险。
一个典型的例子是这样的:
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);
}
}
现在您可以确定您的翻译单元不会对程序的其余部分施加任何过度的链接时间负担。
未命名命名空间的放置是个人喜好问题;您可以将它放在常用的命名空间中,也可以放在顶层。效果是一样的。