模板和匿名命名空间问题
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 在这里没有做错,您的代码根本不可移植。
所以我正在更新一些 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 在这里没有做错,您的代码根本不可移植。