当前位置: 首页 > 知识库问答 >
问题:

静态成员函数使用相同名称时模板类型名称错误

程祺
2023-03-14

我有以下代码:

struct test
{
    static void T()
    {
    }
    
    template<typename T>
    void f(T* t)
    {
    }
    
    template<typename T>
    T* get()
    {
        return new T();     
    }
};

int main()
{
    test t;
    t.f(t.get<int>());
    
    return 0;
}

这段代码编译得很好,但如果我将定义移到类之外,它就不会:

struct test
{
    static void T();
    
    template<typename T>
    void f(T* t);
    
    template<typename T>
    T* get();
};

void test::T()
{
}

template<typename T>
void test::f(T* t)
{
}

template<typename T>
T* test::get()
{
    return new T();     
}

int main()
{
    test t;
    t.f(t.get<int>());
    
    return 0;
}

gcc错误消息:


#1 with x86-64 gcc 9.3
<source>:17:14: error: variable or field 'f' declared void
   17 | void test::f(T* t)
      |              ^
<source>:17:15: error: expected primary-expression before '*' token
   17 | void test::f(T* t)
      |               ^
<source>:17:17: error: 't' was not declared in this scope
   17 | void test::f(T* t)
      |                 ^
Compiler returned: 1

叮当的错误消息:

#1 with x86-64 clang 8.0.0
<source>:17:12: error: variable has incomplete type 'void'
void test::f(T* t)
           ^
<source>:17:17: error: use of undeclared identifier 't'
void test::f(T* t)
                ^
<source>:17:19: error: expected ';' at end of declaration
void test::f(T* t)
                  ^
                  ;
<source>:18:1: error: expected unqualified-id
{
^
<source>:24:16: error: unknown type name 'T'
    return new T();
               ^
5 errors generated.

Compiler returned: 1

MSVC 2019错误消息

#1 with x64 msvc v19.24
example.cpp

<source>(17): error C2065: 't': undeclared identifier
<source>(17): error C2182: 'f': illegal use of type 'void'
<source>(17): error C2350: 'test::f' is not a static member
<source>(17): note: see declaration of 'test::f'
<source>(17): error C2513: 'test::f': no variable declared before '='
<source>(18): error C2447: '{': missing function header (old-style formal list?)
Compiler returned: 2

如果它在测试中将类型名称T更改为类型名称SomeOtherName::f,或者如果我将静态void T()重命名为其他名称,它也可以很好地编译。

你能解释一下为什么第一个版本编译而第二个版本没有编译吗?你能告诉我这个错误的标准措辞吗?

编辑:我发布了来自不同编译器的错误消息。当@cigien pointed clang trunk编译第二个版本时

共有1个答案

林修真
2023-03-14

名称查找对于模板参数来说非常微妙:它们在作用域中的优先级不仅取决于模板头出现的位置,还取决于它为其提供模板参数的实体。[temp.local]/7说

在出现在类模板定义之外的类模板成员的定义中,类模板成员的名称隐藏任何封闭类模板的模板参数的名称(如果成员是类或函数模板,则不隐藏成员的模板参数)。

这在这里并不完全适用(< code>test不是一个类模板),但它表明您的外部定义应该没问题。编译器知道这一点并不容易,因为它需要识别成员来决定它是否是一个成员模板。然而,通过仔细考虑declarator-id的哪一部分使用来自每个模板头的模板参数,这是可能的,所以该规则不应该自动被认为是有缺陷的;铿锵(行李箱!)似乎在这种扩展的意义上正确地应用了它,尽管(正如在一个评论中指出的,也有一个老的CWG问题对这种情况提出了相反的解释。

 类似资料:
  • 问题内容: 在我的Java应用程序中,我使用第三方库。 但是,我发现有些奇怪,有一些嵌套的程序包,有些类的名称可能与程序包的名称相同。 恐怕我不清楚。这是一个例子: 包 在“ com.xx.a”内部有一个名为“ a”的类。 因此,如果我想将此类称为“ a” … 我写: 然后,IDE将认为我的意思是软件包“ com.xx.a.a”。 那我就不能打电话了。 我想知道为什么? 顺便说一句,图书馆提供者似

  • 问题内容: 我有一个Animal类和一个名为AnimalExtension的Animal扩展。 这两个类之间的唯一区别是AnimalExtension还有另一个实例变量叫做animalId。Animal没有此实例变量。 我也有自己的数据类型,想要对XML进行封送处理。此数据类型称为AnimalList。在AnimalList内,有一个Animals列表作为实例变量。 animalList可以包含A

  • 我想问一下java编程语言,具体到构造函数。假设我们有一个类测试,在那里我们测试整个程序,和类点,在那里定义构造函数(集和获取方法btw)。类行: 类点: 现在,如果我在构造函数中输入类点的名称,那将是一个错误:

  • 问题内容: 我在这里已经读到,在Java中,具有相同名称但不同类型的两个变量可以在同一范围内共存。我的意思是这个 但是所有的Java IDE都不允许这样的代码。我想知道这样的代码在语法上是否正确,或者只是IDE不允许这样的代码防止歧义。 无论如何,这是网站的摘录 “如果幸运的话,您也许能够重新编译Jad的输出。 但是,Java VM对于变量命名的规则比Java语言本身更为宽松。例如,一个有效的类文

  • 但所有java IDE都不允许这样的代码。我想知道这样的代码在语法上是否真的正确,或者只是IDE不允许这样的代码来防止歧义。 总之,这里是从网站上摘录的 “如果你幸运的话,你也许可以重新编译JAD的输出。然而,Java VM对变量命名的规则比Java语言本身更宽松。例如,一个有效的类文件可以有几个名为'a'的变量,只要它们有不同的类型。如果你反编译这样的类,你得到的源代码将是无效的。 JAD通常会

  • 考虑以下示例: 使用GCC 5.2编译会引发以下编译错误: 但是标准在14.6.5中说: 友元类或函数可以在类模板中声明。当模板被实例化时,其朋友的名称被视为在实例化点显式声明了专门化。 为什么编译失败?在GCC 3.4中,通过。