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

标签 c++ language-lawyer

我有以下代码:

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
如果更改 typename T,它也可以正常编译至 typename SomeOtherNametest::f或者如果我重命名 static void T()到别的东西。
你能解释一下为什么第一个版本可以编译而第二个版本不能吗?你能指出这个错误的标准措辞吗?
编辑:
我已经发布了来自不同编译器的错误消息。正如@cigien 指出clang trunk 编译第二个版本

最佳答案

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

In the definition of a member of a class template that appears outside of the class template definition, the name of a member of the class template hides the name of a template-parameter of any enclosing class templates (but not a template-parameter of the member if the member is a class or function template).


这在字面上并不适用(test 不是类模板),但它表明您的外部定义应该没问题。编译器知道这一点并不完全是微不足道的,因为它需要 识别成员以决定它是否是成员模板。然而,通过仔细考虑声明符 ID 的哪一部分使用来自每个模板头的模板参数是可能的,因此该规则不应自动被认为是有缺陷的; Clang (trunk!) 似乎在这个扩展的意义上正确地应用了它,尽管(正如在 a comment 中指出的那样)还有一个旧的 CWG 问题暗示了对这种情况的相反解释。

关于c++ - 静态成员函数使用相同名称时模板类型名称错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62597745/

相关文章:

c++ - 多重继承情况下的销毁顺序

c++ - 在C++17中移动/复制构造函数/赋值是否为 "deleted"或 "not declared"是否成立?

c++ - std::unique_ptr::reset 检查托管指针是否为空?

c++ - 阿杜伊诺错误 : too few arguments to function 'int getMode(int, int, int, int, int)'

python - C++ - Python 与 ctypes 的绑定(bind) - 在函数中返回多个值

c++ - 在函数的模板参数上分支?

c++ - 将 50 位二进制值转换为整数

c++ - boost::visit_each 有什么用?

java - 如何理解 Java 语言规范中的 volatile 示例?

c++ - 使用 map 提取和重新插入的限制性规则的基本原理