我有以下代码:
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 SomeOtherName
在 test::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/