模板和匿名命名空间问题

Template and anonymous namespace Issue

所以我正在更新一些 C++11 代码以使用 gcc-11,并且 运行 遇到了问题...

也就是说,在 gcc-11 中,如果构造函数使用模板 class 中的类型,则显式实例化的 class 的构造函数符号似乎不存在,已定义在匿名命名空间中。

下面是产生该问题的简化示例。

Clang-12 和 gcc-8 不会表现出这种行为并导出符号(如我所料)。

template.h:

#pragma once

namespace {
   template <typename T>
   struct MyAnonTempStruct
   {
      typedef float BaseType;
   };
}

template <typename T>
class MyTemplateClass
{
   public: 
   typedef typename MyAnonTempStruct<T>::BaseType BaseType;

   public: 
   MyTemplateClass(const BaseType* array);
};

template.cpp:

#include "template.h"

template <typename T>
MyTemplateClass<T>::MyTemplateClass(const BaseType* array)
{
}

template class MyTemplateClass<float>;

使用编译命令

gcc -c -o template.o template.cpp

使用 nm 我得到以下 Clang-12 和 gcc-8 的符号输出:

0000000000000000 W MyTemplateClass<float>::MyTemplateClass(float const*)
0000000000000000 W MyTemplateClass<float>::MyTemplateClass(float const*)
0000000000000000 n MyTemplateClass<float>::MyTemplateClass(float const*)

对于 gcc-11 我只得到一个文本符号:

0000000000000000 t MyTemplateClass<float>::MyTemplateClass(float const*)

如果我在 header 中将显式特化标记为 extern,那么在 gcc-11 中又可以正常工作了。 即,添加:

extern template class MyTemplateClass<float>;

所以我想我的问题是: 这是预期的行为吗?它之前起作用的事实只是因为它未定义,还是某种形式的错误编译?

通常不应在头文件中使用匿名命名空间。很少有例外,您的用例也不例外。您可以使用 namespace detail 向人们建议里面的代码不适合他们使用。

GCC 11 在这里没有做错,您的代码根本不可移植。