Visual C ++编译器为模糊符号提供错误的行引用

时间:2016-04-15 10:23:52

标签: c++ visual-studio-2015

代码如下:

namespace n1
{
    template <class T>
    void n2();

    template <class T>
    void n2(T);
}

namespace n2 /* line 12 */
{
    class c {};
}

using namespace n1;

namespace n3
{
    void foo(n2::c);
}

void n3::foo(n2::c) /* line 24 */
{

}

尝试使用最新版本的Visual C ++编译时,出现以下错误:

1>test.cpp(24): error C2872: 'n2': ambiguous symbol
1>test.cpp(12): note: could be 'n2'
1>test.cpp(24): note: or       'n2'

第12行和第24行在上一个代码中标有注释。

这里发生了什么?如果我删除foo的定义并在函数参数列表之外声明一个类型为n2 :: c的变量,它编译得很好,我想这是因为编译器指出我引用了类而不是任何一个模板功能。另外,如果相反,我删除命名空间n1中的两个n2模板函数的第二个定义,然后编译器给我一个错误消息,但引用正确的行:第12行和n2被定义为函数的行(而不是第24行) )。这是编译器错误吗?

1 个答案:

答案 0 :(得分:2)

I think Microsoft is correct here. Quoting the working C++ standard draft $7.3.4.6, it says

If name lookup finds a declaration for a name in two different namespaces, and the declarations do not declare the same entity and do not declare functions, the use of the name is ill-formed....

Then it gives an example similar to yours, like this:

namespace A {
  class X { };
  extern "C"   int g();
  extern "C++" int h();
}
namespace B {
  void X(int);
  extern "C"   int g();
  extern "C++" int h(int);
}
using namespace A;
using namespace B;

void f() {
  X(1);             // error: name X found in two namespaces
  g();              // OK: name g refers to the same entity
  h();              // OK: overload resolution selects A::h
}

Though, both gcc and clang accept the code. I think they are wrong here.

Go back to the quoted paragraph and note the line "...do not declare the same entity and do not declare functions...".

In your code, the name n2 in the namespace n1 is a function template and not a function. Because, a function template is not a function. See $8.3.5.15 (emphasis mine):

A non-template function is a function that is not a function template specialization. [ Note: A function template is not a function. — end note ]

To resolve your problem, qualify n2 with a global namespace... like this

namespace n1
{
    template <class T>
    void n2();

    template <class T>
    void n2(T);
}

namespace n2 /* line 12 */
{
    class c {};
}

using namespace n1;

namespace n3
{
    void foo(::n2::c);
}

void n3::foo(::n2::c) /* line 24 */
{

}