在下面的代码中,foo
应该是任何人都可以访问的函数,但是 foo_helper
不应该,这就是为什么我将它放在匿名 namespace 中。显然,我在这个例子中省略了包含守卫和包含,但它们确实存在。
foo.h
:
namespace
{
void foo_helper() {}
template <typename T, typename... Tail>
void foo_helper(T head, Tail... tail)
{
bar(head);
foo_helper(tail...);
}
}
void foo();
template <typename... Args>
void foo(Args... args)
{
before();
foo_helper(args...);
after();
}
foo.cpp
:
void foo() {}
问题是为了 foo_helper
的可变参数模板要工作,它需要具有不带参数的初始版本。但是,这迫使我定义一个非模板函数是一个头文件,在多个源文件中包含该文件后,该函数会中断。我无法移动 foo_helper
的定义到源文件,因为它位于匿名 namespace 中,因为它不应该是可访问的。
有办法解决这个问题吗?
最佳答案
inline void foo_helper() {};
解决您的问题。
inline
主要表示“该函数的冲突定义将被丢弃,并保留其中一个版本”。
它还以模糊的方式无约束力地建议“内联”(因为该标准并未真正涵盖内联是什么)。编译器可能会也可能不会注意该建议。
请注意,匿名命名空间不会“使其变得不可用”或其他什么。匿名命名空间旨在阻止链接器冲突,仅此而已。创建一个名为 details
的命名空间,然后……好吧,相信用户不会去窥探内部。
在 header 中使用匿名命名空间是一个非常糟糕的主意。
如果另一个头文件中有一个内联函数(或模板函数)访问匿名命名空间中的符号或函数,那么几乎肯定会有 ODR(一个定义规则)违反。这就是同一个对象、函数等有两个不同定义的地方,这是不允许的。
例如:
inline void bob() {
foo(1,2,3);
}
如果在两个不同的 .cpp 文件中#include
,那么您刚刚创建了一个格式错误的程序(无需诊断)。
这种格式不正确的程序通常“按照您期望的方式运行”,但有时它们不会。举个例子,如果沿线的某个地方您得到一个静态局部变量,其存在取决于 ODR 违规,则可以让多个编译单元对哪个变量存在及其属性存在分歧。
从更一般的意义上来说,程序的链接顺序可能会改变其行为,因为“选择”了不同的定义(可能存在极其细微的差异)。或者月相也可以起到同样的作用。
ODR 违规行为出人意料地良性,直到它们向您发出难以追踪的非本地错误。
关于c++ - 如何在匿名命名空间中调用可变参数模板助手?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33154578/