代码之家  ›  专栏  ›  技术社区  ›  Fred Larson

未命名命名空间中符号的模板访问

  •  1
  • Fred Larson  · 技术社区  · 14 年前

    我们将我们的XL C/C++编译器从V8.0升级到V8.1,发现一些代码现在给了我们一个错误,即使它是在V8.0下编译的。下面是一个简单的例子:

    试验:H:

    #include <iostream>
    #include <string>
    
    template <class T>
    void f()
    {
      std::cout << TEST << std::endl;
    }
    

    测试:CPP:

    #include <string>
    #include "test.h"
    
    namespace
    {
      std::string TEST = "test";
    }
    
    int main()
    {
      f<int>();
      return 0;
    }
    

    在v10.1下,我们得到以下错误:

    "test.h", line 7.16: 1540-0274 (S) The name lookup for "TEST" did not find a declaration.
    "test.cpp", line 6.15: 1540-1303 (I) "std::string TEST" is not visible.
    "test.h", line 5.6: 1540-0700 (I) The previous message was produced while processing "f<int>()".
    "test.cpp", line 11.3: 1540-0700 (I) The previous message was produced while processing "main()".
    

    我们发现g++3.3.2和4.3.2之间有相似的区别。如果我移动 #include "test.h" 在未命名的命名空间声明之后,编译错误就消失了。

    所以我的问题是:标准对此有何规定?当一个模板被实例化时,这个实例被认为是在模板本身被声明的时候声明的,还是标准在这一点上没有那么清楚?我看了一下n2461.pdf的草稿,但没有真正得出任何确定的结果。

    3 回复  |  直到 14 年前
        1
  •  5
  •   Johannes Schaub - litb    14 年前

    这不是有效的C++代码。 TEST 不依赖于模板参数 T ,因此在分析模板定义时必须在其上下文中找到它。然而,在这种情况下 试验 存在,因此存在错误。

    该格式错误的模板的诊断消息可以延迟到编译器实例化,但如果编译器运行良好,它将更早地诊断错误。即使在模板被实例化时也不为该代码提供任何诊断消息的编译器也不符合要求。它与未命名的命名空间无关。

    另外,请注意,即使将未命名的命名空间放在该模板之上,如果在多个翻译单元中定义并调用该模板,也不会是一个有效的C++程序。这是因为具有相同模板参数的同一模板的不同实例化将引用不同的内容(未命名命名空间中的字符串每次在另一个转换单元中定义时都将生成不同的对象)。这样的程序的行为将是未定义的。

        2
  •  0
  •   Artem Sokolov    14 年前

    记住include只是将.h文件的内容复制到.cpp文件中。所以,f()的定义出现在test的定义之前。最好的解决办法是

    extern std::string TEST;
    

    在.h文件的顶部。

        3
  •  0
  •   fbrereto    14 年前

    此测试未通过 Comeau online compiler 它在过去被证明是最符合标准的编译器之一。因此,我倾向于认为代码是不正确的,尽管我不能在标准中指出原因。不过,请注意,在宽松模式下编译代码会成功。