c++ - 如何在匿名命名空间中调用可变参数模板助手?

标签 c++ c++11 variadic-templates unnamed-namespace

在下面的代码中,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/

相关文章:

c++ - 如何将 gmail 中的 mpz_t 存储在 mongodb 上?

c++ - 使用(递增/递减)运算符而不是变量(+/-)1有什么优点?

c++ - 如何实现平滑的声音衰减效果?

c++ - 如何获取元组 C++ 的前 N ​​个元素?

c++ - Qt5 嘈杂的调试消息 "XI2 mouse release ... source MouseEventNotSynthesized"

c++ - 使用 stdlibc++ 4.7 启用 C++11 时,出现 clang 错误,而 gcc 编译正常

c++ - 如何从我的嵌套模板类中创建静态库?

c++ - 字符串 vector 的高效组合

c++ - 这不能用可变参数模板参数包来完成吗?

c++ - 如何使用可变参数模板在类中定义类型?