我发现某些代码(如下)的这种奇怪情况无法在 Visual Studio 2008 下编译,并在第 12 行产生“错误 C2872:'Ambiguity':不明确的符号”。
删除最后一行上的 using
namespace RequiredNamespace
可以修复错误,但我希望将 using namespace
放在文件末尾应该没有任何效果。它还依赖于 AnotherFunction
作为模板函数,因此我希望编译器在错误的范围内生成模板化函数,或者在执行此操作之前不会重置正在使用的命名空间列表。
相同的代码在 GCC 下编译。
两个编译器似乎都在
TemplatedFunction
定义之后生成 using namespace Namespace
的代码,至少据我通过引入错误并查看它们的输出顺序可以看出。
namespace Ambiguity
{
class cSomeClass
{
};
template<class T>
void TemplatedFunction(T a)
{
// this is where the error occurs, the compiler thinks Ambiguity
// might refer to the class in RequiredNamespace below
Ambiguity::cSomeClass();
}
}
namespace RequiredNamespace
{
// without a namespace around this class, the Ambiguity class
// and namespace collide
class Ambiguity
{
};
}
int main()
{
// to force the templated function to be generated
Ambiguity::TemplatedFunction(4);
}
// removing this removes the error, but it shouldn't really do anything
using namespace RequiredNamespace;
显然这是一个制造的示例,但原件是从真实案例中提取的,其中
using namespace
位于由第 3 方代码生成的自动生成文件中。
这是编译器中的错误吗?
我同意这是一个错误,但是可以通过生成与您的文件相对应的程序集列表(使用 cl.exe 的 /Fa 选项)来了解正在发生的情况。
因此,注释掉 using 声明,生成 .asm 文件并在文本编辑器中打开它。扫描该文件,可以看到模板的实例化位于文件的底部(以
??$TemplatedFunction@H@Ambiguity@@YAXH@Z PROC
开头),并且位于为主函数生成的程序集下方(以_main PROC
开头)。错误消息显示“请参阅对函数模板实例化的引用”,因此它指的是模板函数的实例化,并且程序集列表清楚地表明此实例化位于文件的底部。
现在,编辑代码以用
NonTemplatedFunction(int a)
替换模板函数并编译,生成汇编列表。查看汇编列表,您将看到为 NonTemplatedFunction(int a)
生成的汇编代码出现在 _main PROC
上方。
这些胡言乱语是什么意思?当 Visual Studio 2008 编译器将模板转换为实际代码时,它实际上是在 using 声明之后将一些代码附加到文件末尾。您的 using 声明意味着自动生成的代码中的名称是“不明确的”。 gcc用来实例化模板的过程显然避免了这个问题。
我相信这是一个错误,根据 C++03 标准的 7.3.4 第 1 段:
using-directive 指定指定命名空间中的名称可以在 using-directive 出现在 using-directive 之后的范围内使用。
所以你的文件结尾 using 声明应该没有效果。