views:

96

answers:

2

I've found this odd case of some code (below) doesn't compile under Visual Studio 2008 and produces an "error C2872: 'Ambiguity' : ambiguous symbol" on line 12.

Removing the using namespace RequiredNamespace on the last line fixes the error, but I'd expect that putting using namespace at the end of a file should have no effect. It also relies on AnotherFunction being a template function, so I expect the compiler is generating the templated functions in the wrong scope, or isn't resetting the list of namespaces being used before doing so.

The same code compiles under GCC.

Both compilers seem to generate the code for TemplatedFunction after the using namespace Namespace definition, at least as far as I can tell by introducing errors and looking at the order they're output.

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; 

Obviously this is a manufactured example, but the original is extracted from a real case where the using namespace is in a auto-generated file produced by 3rd party code.

Is this a bug in the compiler?

+2  A: 

I believe it's a bug, per 7.3.4 para 1 of the C++03 standard:

A using-directive specifies that the names in the nominated namespace can be used in the scope in which the using-directive appears after the using-directive.

So your end-of-file using declaration should have no effect.

Mike G.
+5  A: 

I agree that it is a bug, but some insight into what is going on can be obtianed by generating the assembly listing corresponding to your file (use the /Fa option of cl.exe).

So, comment out the using declaration, generate the .asm file and open it in a text editor. Scan the file and you can see that the instantiation of the template is at the bottom of the file (it starts with ??$TemplatedFunction@H@Ambiguity@@YAXH@Z PROC), and it is under the assembly generated for the main function (starts with _main PROC). The error message said "see reference to function template instantiation", so it is referring to the instantiation of the template function, and the assembly listing makes clear this instantiation is at the bottom of the file.

Now, edit the code to replace the template function with NonTemplatedFunction(int a) and compile, generating an assembly listing. View the assembly listing and you will see the assembly code generated for NonTemplatedFunction(int a) appears above _main PROC.

What does all this babble mean? When the Visual Studio 2008 compiler turns your templates into actual code, it is effectively appending some code to the end of your file after your using declaration. Your using declaration means the names in the automatically generated code are "ambiguous". The process gcc uses to instantiate templates obviously avoids this problem.

mcdave
+1: If you changed it to a non-templated function, Intellisense will complain but the file will compile.
DeadMG