在内联匿名命名空间中声明的全局命名空间中定义模板函数时未定义的引用

Undefined reference when defining a template function in the global namespace which is declared in an inline anonymous namespace

鉴于:

namespace ns
{
  inline namespace
  {
    template<typename T>
    void f();
  }
}

template<typename T>
void ns::f() {}

int main()
{
    ns::f<int>();
}

GCC (trunk) 抱怨 ns::f<int> 没有定义。 Clang (trunk) 对此没问题。参见:https://godbolt.org/z/n5qMs85q5

这是 GCC 中的已知错误吗? Clang 不正确吗?

GCC 是对的,程序格式错误。

可以对 inline 命名空间的成员执行的操作在 [namespace.def]/7:

中指定

Members of an inline namespace can be used in most respects as though they were members of the enclosing namespace. Specifically, the inline namespace and its enclosing namespace are both added to the set of associated namespaces used in argument-dependent lookup whenever one of them is, and a using-directive that names the inline namespace is implicitly inserted into the enclosing namespace as for an unnamed namespace. Furthermore, each member of the inline namespace can subsequently be partially specialized, explicitly instantiated, or explicitly specialized as though it were a member of the enclosing namespace. Finally, looking up a name in the enclosing namespace via explicit qualification ([namespace.qual]) will include members of the inline namespace brought in by the using-directive even if there are declarations of that name in the enclosing namespace.

因此,可以查找 inline 命名空间成员,甚至 specialized 使用它的封闭范围名称,但不能 defined.

要定义一个成员,您仍然需要对其进行完全限定。但是你不能限定未命名的命名空间。

要修复它,只需给它起个名字:

namespace ns
{
  inline namespace X
  {
    template<typename T>
    void f();
  }
}

template<typename T>
void ns::X::f()
{
  T t{};
  ++t;
}

奖金信息:

要了解未命名命名空间的工作原理,请参阅 [namespace.unnamed]/1:

An unnamed-namespace-definition behaves as if it were replaced by

inline(opt) namespace unique { /* empty body */ }
using namespace unique ;
namespace unique { namespace-body }

所以一个未命名的命名空间实际上有一个名字,它只是对用户隐藏了。因此,它永远不能完全限定其中的内容(这实际上是重点)。

[namespace.memdef]/2

Members of a named namespace can also be defined outside that namespace by explicit qualification ...

这基本上意味着如果你能限定它,你就可以定义它