Mir*_*pas 8 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;
}
Run Code Online (Sandbox Code Playgroud)
这段代码编译得很好,但如果我将定义移到类之外,它不会:
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;
}
Run Code Online (Sandbox Code Playgroud)
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
Run Code Online (Sandbox Code Playgroud)
叮当错误信息:
#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
Run Code Online (Sandbox Code Playgroud)
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
Run Code Online (Sandbox Code Playgroud)
如果它更改typename T为typename SomeOtherNameintest::f或者我重命名static void T()为其他名称,它也可以很好地编译。
你能解释一下为什么第一个版本可以编译而第二个版本不能吗?你能指出这个错误的标准措辞吗?
编辑:我发布了来自不同编译器的错误消息。正如@cigien 指出clang trunk 编译第二个版本
对于模板参数来说,名称查找非常微妙:它们在范围中的优先级不仅取决于模板头出现的位置,还取决于它为其提供模板参数的实体。[temp.local]/7 说
在出现在类模板定义之外的类模板成员的定义中,类模板成员的名称隐藏了任何封闭类模板的模板参数的名称(但不隐藏类模板的模板参数的名称)。成员(如果成员是类或函数模板)。
这并不真正适用于这里(test不是类模板),但它表明您的外线定义应该没问题。对于编译器来说,知道这一点并非完全无关紧要,因为它需要识别成员才能决定它是否是成员模板。但是,通过仔细考虑declarator-id的哪一部分使用每个template-head中的模板参数是可能的,因此该规则不应自动被视为有缺陷;Clang(trunk!)似乎在这种扩展意义上正确应用了它,尽管(正如评论中指出的,还有一个旧的 CWG 问题建议对此案例进行相反的解释。
| 归档时间: |
|
| 查看次数: |
125 次 |
| 最近记录: |